255 prev next chunks index CyanogenMod/android_packages_apps_Trebuchet_5b437d8957c21b5fab42d3540db39da09378cfd7_src/com/android/launcher3/LauncherModel.java {strict: [[bsj]], subset: [[bsj]]}
line based (standard git) jfstmerge spork
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.app.SearchManager;                                                                        
  20 import android.appwidget.AppWidgetProviderInfo;                                                          
  21 import android.content.BroadcastReceiver;                                                                
  22 import android.content.ComponentName;                                                                    
  23 import android.content.ContentProviderClient;                                                            
  24 import android.content.ContentProviderOperation;                                                         
  25 import android.content.ContentResolver;                                                                  
  26 import android.content.ContentValues;                                                                    
  27 import android.content.Context;                                                                          
  28 import android.content.Intent;                                                                           
  29 import android.content.Intent.ShortcutIconResource;                                                      
  30 import android.content.IntentFilter;                                                                     
  31 import android.content.SharedPreferences;                                                                
  32 import android.content.pm.PackageManager;                                                                
  33 import android.content.pm.ProviderInfo;                                                                  
  34 import android.content.pm.ResolveInfo;                                                                   
  35 import android.content.res.Configuration;                                                                
  36 import android.content.res.Resources;                                                                    
  37 import android.database.Cursor;                                                                          
  38 import android.graphics.Bitmap;                                                                          
  39 import android.graphics.Rect;                                                                            
  40 import android.net.Uri;                                                                                  
  41 import android.os.Environment;                                                                           
  42 import android.os.Handler;                                                                               
  43 import android.os.HandlerThread;                                                                         
  44 import android.os.Parcelable;                                                                            
  45 import android.os.Process;                                                                               
  46 import android.os.RemoteException;                                                                       
  47 import android.os.SystemClock;                                                                           
  48 import android.provider.BaseColumns;                                                                     
  49 import android.text.TextUtils;                                                                           
  50 import android.util.Log;                                                                                 
  51 import android.util.LongSparseArray;                                                                     
  52 import android.util.Pair;                                                                                
  53                                                                                                          
  54 import com.android.launcher3.compat.AppWidgetManagerCompat;                                              
  55 import com.android.launcher3.compat.LauncherActivityInfoCompat;                                          
  56 import com.android.launcher3.compat.LauncherAppsCompat;                                                  
  57 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  58 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  59 import com.android.launcher3.compat.UserHandleCompat;                                                    
  60 import com.android.launcher3.compat.UserManagerCompat;                                                   
  61                                                                                                          
  62 import java.lang.ref.WeakReference;                                                                      
  63 import java.net.URISyntaxException;                                                                      
  64 import java.security.InvalidParameterException;                                                          
  65 import java.text.Collator;                                                                               
  66 import java.util.ArrayList;                                                                              
  67 import java.util.Arrays;                                                                                 
  68 import java.util.Collection;                                                                             
  69 import java.util.Collections;                                                                            
  70 import java.util.Comparator;                                                                             
  71 import java.util.HashMap;                                                                                
  72 import java.util.HashSet;                                                                                
  73 import java.util.Iterator;                                                                               
  74 import java.util.List;                                                                                   
  75 import java.util.Map.Entry;                                                                              
  76 import java.util.Set;                                                                                    
  77                                                                                                          
  78 /**                                                                                                      
  79  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  80  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  81  * for the Launcher.                                                                                     
  82  */                                                                                                      
  83 public class LauncherModel extends BroadcastReceiver                                                     
  84         implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                      
  85     static final boolean DEBUG_LOADERS = false;                                                          
  86     private static final boolean DEBUG_RECEIVER = false;                                                 
  87     private static final boolean REMOVE_UNRESTORED_ICONS = true;                                         
  88     private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                  
  89                                                                                                          
  90     static final String TAG = "Launcher.Model";                                                          
  91                                                                                                          
  92     public static final int LOADER_FLAG_NONE = 0;                                                        
  93     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  94     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  95                                                                                                          
  96     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  97     private static final long INVALID_SCREEN_ID = -1L;                                                   
  98                                                                                                          
  99     private final boolean mAppsCanBeOnRemoveableStorage;                                                 
 100     private final boolean mOldContentProviderExists;                                                     
 101                                                                                                          
 102     private final LauncherAppState mApp;                                                                 
 103     private final Object mLock = new Object();                                                           
 104     private DeferredHandler mHandler = new DeferredHandler();                                            
 105     private LoaderTask mLoaderTask;                                                                      
 106     private boolean mIsLoaderTaskRunning;                                                                
 107                                                                                                          
 108     /**                                                                                                  
 109      * Maintain a set of packages per user, for which we added a shortcut on the workspace.              
 110      */                                                                                                  
 111     private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";    
 112                                                                                                          
 113     // Specific runnable types that are run on the main thread deferred handler, this allows us to       
 114     // clear all queued binding runnables when the Launcher activity is destroyed.                       
 115     private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                            
 116     private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                           
 117                                                                                                          
 118     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                    
 119                                                                                                          
 120     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");             
 121     static {                                                                                             
 122         sWorkerThread.start();                                                                           
 123     }                                                                                                    
 124     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                       
 125                                                                                                          
 126     // We start off with everything not loaded.  After that, we assume that                              
 127     // our monitoring of the package manager provides all updates and we never                           
 128     // need to do a requery.  These are only ever touched from the loader thread.                        
 129     private boolean mWorkspaceLoaded;                                                                    
 130     private boolean mAllAppsLoaded;                                                                      
 131                                                                                                          
 132     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 133     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 134     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 135     // a normal load, we also clear this set of Runnables.                                               
 136     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 137                                                                                                          
 138     private WeakReference<Callbacks> mCallbacks;                                                         
 139                                                                                                          
 140     // < only access in worker thread >                                                                  
 141     AllAppsList mBgAllAppsList;                                                                          
 142                                                                                                          
 143     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 144     // other locks, this one can generally be held long-term because we never expect any of these        
 145     // static data structures to be referenced outside of the worker thread except on the first          
 146     // load after configuration change.                                                                  
 147     static final Object sBgLock = new Object();                                                          
 148                                                                                                          
 149     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 150     // LauncherModel to their ids                                                                        
 151     static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                  
 152                                                                                                          
 153     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 154     //       created by LauncherModel that are directly on the home screen (however, no widgets or       
 155     //       shortcuts within folders).                                                                  
 156     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 157                                                                                                          
 158     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 159     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 160         new ArrayList<LauncherAppWidgetInfo>();                                                          
 161                                                                                                          
 162     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 163     static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                 
 164                                                                                                          
 165     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 166     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 167                                                                                                          
 168     // sBgWidgetProviders is the set of widget providers including custom internal widgets               
 169     public static HashMap<ComponentName, LauncherAppWidgetProviderInfo> sBgWidgetProviders;              
 170     public static boolean sWidgetProvidersDirty;                                                         
 171                                                                                                          
 172     // sPendingPackages is a set of packages which could be on sdcard and are not available yet          
 173     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                           
 174             new HashMap<UserHandleCompat, HashSet<String>>();                                            
 175                                                                                                          
 176     // </ only access in worker thread >                                                                 
 177                                                                                                          
 178     private IconCache mIconCache;                                                                        
 179                                                                                                          
 180     protected int mPreviousConfigMcc;                                                                    
 181                                                                                                          
 182     private final LauncherAppsCompat mLauncherApps;                                                      
 183     private final UserManagerCompat mUserManager;                                                        
 184                                                                                                          
 185     public interface Callbacks {                                                                         
 186         public boolean setLoadOnResume();                                                                
 187         public int getCurrentWorkspaceScreen();                                                          
 188         public void startBinding();                                                                      
 189         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 190                               boolean forceAnimateIcons);                                                
 191         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 192         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 193         public void bindFolders(HashMap<Long,FolderInfo> folders);                                       
 194         public void finishBindingItems();                                                                
 195         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 196         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 197         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 198                                   ArrayList<ItemInfo> addNotAnimated,                                    
 199                                   ArrayList<ItemInfo> addAnimated,                                       
 200                                   ArrayList<AppInfo> addedApps);                                         
 201         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 202         public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                
 203                 ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                 
 204         public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                       
 205         public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);                       
 206         public void updatePackageBadge(String packageName);                                              
 207         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 208                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                 
 209         public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                          
 210         public void bindSearchablesChanged();                                                            
 211         public boolean isAllAppsButtonRank(int rank);                                                    
 212         public void onPageBoundSynchronously(int page);                                                  
 213         public void dumpLogsToLocalData();                                                               
 214         public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,           
 215                 int[] cell, int spanX, int spanY);                                                       
 216     }                                                                                                    
 217                                                                                                          
 218     public interface ItemInfoFilter {                                                                    
 219         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                     
 220     }                                                                                                    
 221                                                                                                          
 222     public interface ScreenPosProvider {                                                                 
 223         int getScreenIndex(ArrayList<Long> screenIDs);                                                   
 224     }                                                                                                    
 225                                                                                                          
 226     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 227         Context context = app.getContext();                                                              
 228                                                                                                          
 229         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 230         String oldProvider = context.getString(R.string.old_launcher_provider_uri);                      
 231         // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different               
 232         // resource string.                                                                              
 233         String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                
 234         ProviderInfo providerInfo =                                                                      
 235                 context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                
 236         ProviderInfo redirectProvider =                                                                  
 237                 context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                
 238                                                                                                          
 239         Log.d(TAG, "Old launcher provider: " + oldProvider);                                             
 240         mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                
 241                                                                                                          
 242         if (mOldContentProviderExists) {                                                                 
 243             Log.d(TAG, "Old launcher provider exists.");                                                 
 244         } else {                                                                                         
 245             Log.d(TAG, "Old launcher provider does not exist.");                                         
 246         }                                                                                                
 247                                                                                                          
 248         mApp = app;                                                                                      
 249         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 250         mIconCache = iconCache;                                                                          
 251                                                                                                          
 252         final Resources res = context.getResources();                                                    
 253         Configuration config = res.getConfiguration();                                                   
 254         mPreviousConfigMcc = config.mcc;                                                                 
 255         mLauncherApps = LauncherAppsCompat.getInstance(context);                                         
 256         mUserManager = UserManagerCompat.getInstance(context);                                           
 257     }                                                                                                    
 258                                                                                                          
 259     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 260      * posted on the main thread handler. */                                                             
 261     private void runOnMainThread(Runnable r) {                                                           
 262         runOnMainThread(r, 0);                                                                           
 263     }                                                                                                    
 264     private void runOnMainThread(Runnable r, int type) {                                                 
 265         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 266             // If we are on the worker thread, post onto the main handler                                
 267             mHandler.post(r);                                                                            
 268         } else {                                                                                         
 269             r.run();                                                                                     
 270         }                                                                                                
 271     }                                                                                                    
 272                                                                                                          
 273     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 274      * posted on the worker thread handler. */                                                           
 275     private static void runOnWorkerThread(Runnable r) {                                                  
 276         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 277             r.run();                                                                                     
 278         } else {                                                                                         
 279             // If we are not on the worker thread, then post to the worker handler                       
 280             sWorker.post(r);                                                                             
 281         }                                                                                                
 282     }                                                                                                    
 283                                                                                                          
 284     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 285         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 286     }                                                                                                    
 287                                                                                                          
 288     public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                       
 289         // Process the updated package state                                                             
 290         Runnable r = new Runnable() {                                                                    
 291             public void run() {                                                                          
 292                 Callbacks callbacks = getCallback();                                                     
 293                 if (callbacks != null) {                                                                 
 294                     callbacks.updatePackageState(installInfo);                                           
 295                 }                                                                                        
 296             }                                                                                            
 297         };                                                                                               
 298         mHandler.post(r);                                                                                
 299     }                                                                                                    
 300                                                                                                          
 301     public void updatePackageBadge(final String packageName) {                                           
 302         // Process the updated package badge                                                             
 303         Runnable r = new Runnable() {                                                                    
 304             public void run() {                                                                          
 305                 Callbacks callbacks = getCallback();                                                     
 306                 if (callbacks != null) {                                                                 
 307                     callbacks.updatePackageBadge(packageName);                                           
 308                 }                                                                                        
 309             }                                                                                            
 310         };                                                                                               
 311         mHandler.post(r);                                                                                
 312     }                                                                                                    
 313                                                                                                          
 314     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 315         final Callbacks callbacks = getCallback();                                                       
 316                                                                                                          
 317         if (allAppsApps == null) {                                                                       
 318             throw new RuntimeException("allAppsApps must not be null");                                  
 319         }                                                                                                
 320         if (allAppsApps.isEmpty()) {                                                                     
 321             return;                                                                                      
 322         }                                                                                                
 323                                                                                                          
 324         // Process the newly added applications and add them to the database first                       
 325         Runnable r = new Runnable() {                                                                    
 326             public void run() {                                                                          
 327                 runOnMainThread(new Runnable() {                                                         
 328                     public void run() {                                                                  
 329                         Callbacks cb = getCallback();                                                    
 330                         if (callbacks == cb && cb != null) {                                             
 331                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 332                         }                                                                                
 333                     }                                                                                    
 334                 });                                                                                      
 335             }                                                                                            
 336         };                                                                                               
 337         runOnWorkerThread(r);                                                                            
 338     }                                                                                                    
 339                                                                                                          
 340     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 341             final ArrayList<ItemInfo> workspaceApps) {                                                   
 342         addAndBindAddedWorkspaceApps(context, workspaceApps,                                             
 343                 new ScreenPosProvider() {                                                                
 344                                                                                                          
 345                     @Override                                                                            
 346                     public int getScreenIndex(ArrayList<Long> screenIDs) {                               
 347                         return screenIDs.isEmpty() ? 0 : 1;                                              
 348                     }                                                                                    
 349                 }, 1, false);                                                                            
 350     }                                                                                                    
 351                                                                                                          
 352     private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,               
 353             int[] xy, int spanX, int spanY) {                                                            
 354         LauncherAppState app = LauncherAppState.getInstance();                                           
 355         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 356         final int xCount = (int) grid.numColumns;                                                        
 357         final int yCount = (int) grid.numRows;                                                           
 358         boolean[][] occupied = new boolean[xCount][yCount];                                              
 359         if (occupiedPos != null) {                                                                       
 360             for (Rect r : occupiedPos) {                                                                 
 361                 for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                         
 362                     for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                     
 363                         occupied[x][y] = true;                                                           
 364                     }                                                                                    
 365                 }                                                                                        
 366             }                                                                                            
 367         }                                                                                                
 368         return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                    
 369     }                                                                                                    
 370                                                                                                          
 371     /**                                                                                                  
 372      * Find a position on the screen for the given size or adds a new screen.                            
 373      * @return screenId and the coordinates for the item.                                                
 374      */                                                                                                  
 375     private static Pair<Long, int[]> findSpaceForItem(                                                   
 376             Context context,                                                                             
 377             ScreenPosProvider preferredScreen,                                                           
 378             int fallbackStartScreen,                                                                     
 379             ArrayList<Long> workspaceScreens,                                                            
 380             ArrayList<Long> addedWorkspaceScreensFinal,                                                  
 381             int spanX, int spanY) {                                                                      
 382         // Load position of items which are on the desktop. We can't use sBgItemsIdMap because           
 383         // loadWorkspace() may not have been called.                                                     
 384         final ContentResolver cr = context.getContentResolver();                                         
 385         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 386                 new String[] {                                                                           
 387                     LauncherSettings.Favorites.SCREEN,                                                   
 388                     LauncherSettings.Favorites.CELLX,                                                    
 389                     LauncherSettings.Favorites.CELLY,                                                    
 390                     LauncherSettings.Favorites.SPANX,                                                    
 391                     LauncherSettings.Favorites.SPANY,                                                    
 392                     LauncherSettings.Favorites.CONTAINER                                                 
 393                  },                                                                                      
 394                  "container=?",                                                                          
 395                  new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },        
 396                  null);                                                                                  
 397                                                                                                          
 398         final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);              
 399         final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                
 400         final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                
 401         final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                
 402         final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                
 403         LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();           
 404         try {                                                                                            
 405             while (c.moveToNext()) {                                                                     
 406                 Rect rect = new Rect();                                                                  
 407                 rect.left = c.getInt(cellXIndex);                                                        
 408                 rect.top = c.getInt(cellYIndex);                                                         
 409                 rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                              
 410                 rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                              
 411                                                                                                          
 412                 long screenId = c.getInt(screenIndex);                                                   
 413                 ArrayList<Rect> items = screenItems.get(screenId);                                       
 414                 if (items == null) {                                                                     
 415                     items = new ArrayList<Rect>();                                                       
 416                     screenItems.put(screenId, items);                                                    
 417                 }                                                                                        
 418                 items.add(rect);                                                                         
 419             }                                                                                            
 420         } catch (Exception e) {                                                                          
 421             screenItems.clear();                                                                         
 422         } finally {                                                                                      
 423             c.close();                                                                                   
 424         }                                                                                                
 425                                                                                                          
 426         // Find appropriate space for the item.                                                          
 427         long screenId = 0;                                                                               
 428         int[] cordinates = new int[2];                                                                   
 429         boolean found = false;                                                                           
 430                                                                                                          
 431         int screenCount = workspaceScreens.size();                                                       
 432         // First check the preferred screen.                                                             
 433         int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                     
 434         if (preferredScreenIndex < screenCount) {                                                        
 435             screenId = workspaceScreens.get(preferredScreenIndex);                                       
 436             found = findNextAvailableIconSpaceInScreen(                                                  
 437                     screenItems.get(screenId), cordinates, spanX, spanY);                                
 438         }                                                                                                
 439                                                                                                          
 440         if (!found) {                                                                                    
 441             // Search on any of the screens.                                                             
 442             for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                     
 443                 screenId = workspaceScreens.get(screen);                                                 
 444                 if (findNextAvailableIconSpaceInScreen(                                                  
 445                         screenItems.get(screenId), cordinates, spanX, spanY)) {                          
 446                     // We found a space for it                                                           
 447                     found = true;                                                                        
 448                     break;                                                                               
 449                 }                                                                                        
 450             }                                                                                            
 451         }                                                                                                
 452                                                                                                          
 453         if (!found) {                                                                                    
 454             // Still no position found. Add a new screen to the end.                                     
 455             screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                     
 456                                                                                                          
 457             // Save the screen id for binding in the workspace                                           
 458             workspaceScreens.add(screenId);                                                              
 459             addedWorkspaceScreensFinal.add(screenId);                                                    
 460                                                                                                          
 461             // If we still can't find an empty space, then God help us all!!!                            
 462             if (!findNextAvailableIconSpaceInScreen(                                                     
 463                     screenItems.get(screenId), cordinates, spanX, spanY)) {                              
 464                 throw new RuntimeException("Can't find space to add the item");                          
 465             }                                                                                            
 466         }                                                                                                
 467         return Pair.create(screenId, cordinates);                                                        
 468     }                                                                                                    
 469                                                                                                          
 470     /**                                                                                                  
 471      * Adds the provided items to the workspace.                                                         
 472      * @param preferredScreen the screen where we should try to add the app first                        
 473      * @param fallbackStartScreen the screen to start search for empty space if                          
 474      * preferredScreen is not available.                                                                 
 475      */                                                                                                  
 476     public void addAndBindPendingItem(                                                                   
 477             final Context context,                                                                       
 478             final PendingAddItemInfo addInfo,                                                            
 479             final ScreenPosProvider preferredScreen,                                                     
 480             final int fallbackStartScreen) {                                                             
 481         final Callbacks callbacks = getCallback();                                                       
 482         // Process the newly added applications and add them to the database first                       
 483         Runnable r = new Runnable() {                                                                    
 484             public void run() {                                                                          
 485                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 486                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 487                                                                                                          
 488                 // Find appropriate space for the item.                                                  
 489                 Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                    
 490                         fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,               
 491                         addInfo.spanX,                                                                   
 492                         addInfo.spanY);                                                                  
 493                 final long screenId = coords.first;                                                      
 494                 final int[] cordinates = coords.second;                                                  
 495                                                                                                          
 496                 // Update the workspace screens                                                          
 497                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 498                 runOnMainThread(new Runnable() {                                                         
 499                     public void run() {                                                                  
 500                         Callbacks cb = getCallback();                                                    
 501                         if (callbacks == cb && cb != null) {                                             
 502                             cb.bindAddScreens(addedWorkspaceScreensFinal);                               
 503                             cb.bindAddPendingItem(addInfo,                                               
 504                                     LauncherSettings.Favorites.CONTAINER_DESKTOP,                        
 505                                     screenId, cordinates, addInfo.spanX, addInfo.spanY);                 
 506                         }                                                                                
 507                     }                                                                                    
 508                 });                                                                                      
 509             }                                                                                            
 510         };                                                                                               
 511         runOnWorkerThread(r);                                                                            
 512     }                                                                                                    
 513                                                                                                          
 514     /**                                                                                                  
 515      * Adds the provided items to the workspace.                                                         
 516      * @param preferredScreen the screen where we should try to add the app first                        
 517      * @param fallbackStartScreen the screen to start search for empty space if                          
 518      * preferredScreen is not available.                                                                 
 519      */                                                                                                  
 520     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 521             final ArrayList<ItemInfo> workspaceApps,                                                     
 522             final ScreenPosProvider preferredScreen,                                                     
 523             final int fallbackStartScreen,                                                               
 524             final boolean allowDuplicate) {                                                              
 525         final Callbacks callbacks = getCallback();                                                       
 526         if (workspaceApps.isEmpty()) {                                                                   
 527             return;                                                                                      
 528         }                                                                                                
 529         // Process the newly added applications and add them to the database first                       
 530         Runnable r = new Runnable() {                                                                    
 531             public void run() {                                                                          
 532                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 533                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 534                                                                                                          
 535                 // Get the list of workspace screens.  We need to append to this list and                
 536                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 537                 // called.                                                                               
 538                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 539                 synchronized(sBgLock) {                                                                  
 540                     for (ItemInfo item : workspaceApps) {                                                
 541                         if (!allowDuplicate) {                                                           
 542                             // Short-circuit this logic if the icon exists somewhere on the workspace    
 543                             if (shortcutExists(context, item.title.toString(),                           
 544                                     item.getIntent(), item.user)) {                                      
 545                                 continue;                                                                
 546                             }                                                                            
 547                         }                                                                                
 548                                                                                                          
 549                         // Find appropriate space for the item.                                          
 550                         Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,            
 551                                 fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,       
 552                                 1, 1);                                                                   
 553                         long screenId = coords.first;                                                    
 554                         int[] cordinates = coords.second;                                                
 555                                                                                                          
 556                         ShortcutInfo shortcutInfo;                                                       
 557                         if (item instanceof ShortcutInfo) {                                              
 558                             shortcutInfo = (ShortcutInfo) item;                                          
 559                         } else if (item instanceof AppInfo) {                                            
 560                             shortcutInfo = ((AppInfo) item).makeShortcut();                              
 561                         } else {                                                                         
 562                             throw new RuntimeException("Unexpected info type");                          
 563                         }                                                                                
 564                                                                                                          
 565                         // Add the shortcut to the db                                                    
 566                         addItemToDatabase(context, shortcutInfo,                                         
 567                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 568                                 screenId, cordinates[0], cordinates[1], false);                          
 569                         // Save the ShortcutInfo for binding in the workspace                            
 570                         addedShortcutsFinal.add(shortcutInfo);                                           
 571                     }                                                                                    
 572                 }                                                                                        
 573                                                                                                          
 574                 // Update the workspace screens                                                          
 575                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 576                                                                                                          
 577                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 578                     runOnMainThread(new Runnable() {                                                     
 579                         public void run() {                                                              
 580                             Callbacks cb = getCallback();                                                
 581                             if (callbacks == cb && cb != null) {                                         
 582                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 583                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 584                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 585                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 586                                     long lastScreenId = info.screenId;                                   
 587                                     for (ItemInfo i : addedShortcutsFinal) {                             
 588                                         if (i.screenId == lastScreenId) {                                
 589                                             addAnimated.add(i);                                          
 590                                         } else {                                                         
 591                                             addNotAnimated.add(i);                                       
 592                                         }                                                                
 593                                     }                                                                    
 594                                 }                                                                        
 595                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 596                                         addNotAnimated, addAnimated, null);                              
 597                             }                                                                            
 598                         }                                                                                
 599                     });                                                                                  
 600                 }                                                                                        
 601             }                                                                                            
 602         };                                                                                               
 603         runOnWorkerThread(r);                                                                            
 604     }                                                                                                    
 605                                                                                                          
 606     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 607         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 608             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 609                     "main thread");                                                                      
 610         }                                                                                                
 611                                                                                                          
 612         // Clear any deferred bind runnables                                                             
 613         synchronized (mDeferredBindRunnables) {                                                          
 614             mDeferredBindRunnables.clear();                                                              
 615         }                                                                                                
 616         // Remove any queued bind runnables                                                              
 617         mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                 
 618         // Unbind all the workspace items                                                                
 619         unbindWorkspaceItemsOnMainThread();                                                              
 620     }                                                                                                    
 621                                                                                                          
 622     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 623     void unbindWorkspaceItemsOnMainThread() {                                                            
 624         // Ensure that we don't use the same workspace items data structure on the main thread           
 625         // by making a copy of workspace items first.                                                    
 626         final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                         
 627         final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                             
 628         synchronized (sBgLock) {                                                                         
 629             tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                 
 630             tmpAppWidgets.addAll(sBgAppWidgets);                                                         
 631         }                                                                                                
 632         Runnable r = new Runnable() {                                                                    
 633                 @Override                                                                                
 634                 public void run() {                                                                      
 635                    for (ItemInfo item : tmpWorkspaceItems) {                                             
 636                        item.unbind();                                                                    
 637                    }                                                                                     
 638                    for (ItemInfo item : tmpAppWidgets) {                                                 
 639                        item.unbind();                                                                    
 640                    }                                                                                     
 641                 }                                                                                        
 642             };                                                                                           
 643         runOnMainThread(r);                                                                              
 644     }                                                                                                    
 645                                                                                                          
 646     /**                                                                                                  
 647      * Adds an item to the DB if it was not created previously, or move it to a new                      
 648      * <container, screen, cellX, cellY>                                                                 
 649      */                                                                                                  
 650     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 651             long screenId, int cellX, int cellY) {                                                       
 652         if (item.container == ItemInfo.NO_ID) {                                                          
 653             // From all apps                                                                             
 654             addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                  
 655         } else {                                                                                         
 656             // From somewhere else                                                                       
 657             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 658         }                                                                                                
 659     }                                                                                                    
 660                                                                                                          
 661     static void checkItemInfoLocked(                                                                     
 662             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 663         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 664         if (modelItem != null && item != modelItem) {                                                    
 665             // check all the data is consistent                                                          
 666             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 667                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 668                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 669                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 670                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 671                         modelShortcut.id == shortcut.id &&                                               
 672                         modelShortcut.itemType == shortcut.itemType &&                                   
 673                         modelShortcut.container == shortcut.container &&                                 
 674                         modelShortcut.screenId == shortcut.screenId &&                                   
 675                         modelShortcut.cellX == shortcut.cellX &&                                         
 676                         modelShortcut.cellY == shortcut.cellY &&                                         
 677                         modelShortcut.spanX == shortcut.spanX &&                                         
 678                         modelShortcut.spanY == shortcut.spanY &&                                         
 679                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 680                         (modelShortcut.dropPos != null &&                                                
 681                                 shortcut.dropPos != null &&                                              
 682                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 683                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 684                     // For all intents and purposes, this is the same object                             
 685                     return;                                                                              
 686                 }                                                                                        
 687             }                                                                                            
 688                                                                                                          
 689             // the modelItem needs to match up perfectly with item if our model is                       
 690             // to be consistent with the database-- for now, just require                                
 691             // modelItem == item or the equality check above                                             
 692             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 693                     "modelItem: " +                                                                      
 694                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 695                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 696             RuntimeException e = new RuntimeException(msg);                                              
 697             if (stackTrace != null) {                                                                    
 698                 e.setStackTrace(stackTrace);                                                             
 699             }                                                                                            
 700             throw e;                                                                                     
 701         }                                                                                                
 702     }                                                                                                    
 703                                                                                                          
 704     static void checkItemInfo(final ItemInfo item) {                                                     
 705         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 706         final long itemId = item.id;                                                                     
 707         Runnable r = new Runnable() {                                                                    
 708             public void run() {                                                                          
 709                 synchronized (sBgLock) {                                                                 
 710                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 711                 }                                                                                        
 712             }                                                                                            
 713         };                                                                                               
 714         runOnWorkerThread(r);                                                                            
 715     }                                                                                                    
 716                                                                                                          
 717     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 718             final ItemInfo item, final String callingFunction) {                                         
 719         final long itemId = item.id;                                                                     
 720         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                         
 721         final ContentResolver cr = context.getContentResolver();                                         
 722                                                                                                          
 723         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 724         Runnable r = new Runnable() {                                                                    
 725             public void run() {                                                                          
 726                 cr.update(uri, values, null, null);                                                      
 727                 updateItemArrays(item, itemId, stackTrace);                                              
 728             }                                                                                            
 729         };                                                                                               
 730         runOnWorkerThread(r);                                                                            
 731     }                                                                                                    
 732                                                                                                          
 733     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 734             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 735         final ContentResolver cr = context.getContentResolver();                                         
 736                                                                                                          
 737         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 738         Runnable r = new Runnable() {                                                                    
 739             public void run() {                                                                          
 740                 ArrayList<ContentProviderOperation> ops =                                                
 741                         new ArrayList<ContentProviderOperation>();                                       
 742                 int count = items.size();                                                                
 743                 for (int i = 0; i < count; i++) {                                                        
 744                     ItemInfo item = items.get(i);                                                        
 745                     final long itemId = item.id;                                                         
 746                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);             
 747                     ContentValues values = valuesList.get(i);                                            
 748                                                                                                          
 749                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 750                     updateItemArrays(item, itemId, stackTrace);                                          
 751                                                                                                          
 752                 }                                                                                        
 753                 try {                                                                                    
 754                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 755                 } catch (Exception e) {                                                                  
 756                     e.printStackTrace();                                                                 
 757                 }                                                                                        
 758             }                                                                                            
 759         };                                                                                               
 760         runOnWorkerThread(r);                                                                            
 761     }                                                                                                    
 762                                                                                                          
 763     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 764         // Lock on mBgLock *after* the db operation                                                      
 765         synchronized (sBgLock) {                                                                         
 766             checkItemInfoLocked(itemId, item, stackTrace);                                               
 767                                                                                                          
 768             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 769                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 770                 // Item is in a folder, make sure this folder exists                                     
 771                 if (!sBgFolders.containsKey(item.container)) {                                           
 772                     // An items container is being set to a that of an item which is not in              
 773                     // the list of Folders.                                                              
 774                     String msg = "item: " + item + " container being set to: " +                         
 775                             item.container + ", not in the list of folders";                             
 776                     Log.e(TAG, msg);                                                                     
 777                 }                                                                                        
 778             }                                                                                            
 779                                                                                                          
 780             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 781             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 782             // that are on the desktop, as appropriate                                                   
 783             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 784             if (modelItem != null &&                                                                     
 785                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 786                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 787                 switch (modelItem.itemType) {                                                            
 788                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 789                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 790                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 791                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 792                             sBgWorkspaceItems.add(modelItem);                                            
 793                         }                                                                                
 794                         break;                                                                           
 795                     default:                                                                             
 796                         break;                                                                           
 797                 }                                                                                        
 798             } else {                                                                                     
 799                 sBgWorkspaceItems.remove(modelItem);                                                     
 800             }                                                                                            
 801         }                                                                                                
 802     }                                                                                                    
 803                                                                                                          
 804     /**                                                                                                  
 805      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 806      */                                                                                                  
 807     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,           
 808             final long screenId, final int cellX, final int cellY) {                                     
 809         item.container = container;                                                                      
 810         item.cellX = cellX;                                                                              
 811         item.cellY = cellY;                                                                              
 812                                                                                                          
 813         // We store hotseat items in canonical form which is this orientation invariant position         
 814         // in the hotseat                                                                                
 815         if (context instanceof Launcher && screenId < 0 &&                                               
 816                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 817             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 818         } else {                                                                                         
 819             item.screenId = screenId;                                                                    
 820         }                                                                                                
 821                                                                                                          
 822         final ContentValues values = new ContentValues();                                                
 823         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 824         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 825         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 826         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 827         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 828                                                                                                          
 829         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 830     }                                                                                                    
 831                                                                                                          
 832     /**                                                                                                  
 833      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 834      * cellX, cellY have already been updated on the ItemInfos.                                          
 835      */                                                                                                  
 836     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 837             final long container, final int screen) {                                                    
 838                                                                                                          
 839         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 840         int count = items.size();                                                                        
 841                                                                                                          
 842         for (int i = 0; i < count; i++) {                                                                
 843             ItemInfo item = items.get(i);                                                                
 844             item.container = container;                                                                  
 845                                                                                                          
 846             // We store hotseat items in canonical form which is this orientation invariant position     
 847             // in the hotseat                                                                            
 848             if (context instanceof Launcher && screen < 0 &&                                             
 849                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 850                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 851                         item.cellY);                                                                     
 852             } else {                                                                                     
 853                 item.screenId = screen;                                                                  
 854             }                                                                                            
 855                                                                                                          
 856             final ContentValues values = new ContentValues();                                            
 857             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 858             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 859             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 860             values.put(LauncherSettings.Favorites.RANK, item.rank);                                      
 861             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 862                                                                                                          
 863             contentValues.add(values);                                                                   
 864         }                                                                                                
 865         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 866     }                                                                                                    
 867                                                                                                          
 868     /**                                                                                                  
 869      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 870      */                                                                                                  
 871     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 872             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 873         item.container = container;                                                                      
 874         item.cellX = cellX;                                                                              
 875         item.cellY = cellY;                                                                              
 876         item.spanX = spanX;                                                                              
 877         item.spanY = spanY;                                                                              
 878                                                                                                          
 879         // We store hotseat items in canonical form which is this orientation invariant position         
 880         // in the hotseat                                                                                
 881         if (context instanceof Launcher && screenId < 0 &&                                               
 882                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 883             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 884         } else {                                                                                         
 885             item.screenId = screenId;                                                                    
 886         }                                                                                                
 887                                                                                                          
 888         final ContentValues values = new ContentValues();                                                
 889         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 890         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 891         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 892         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 893         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 894         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 895         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 896                                                                                                          
 897         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 898     }                                                                                                    
 899                                                                                                          
 900     /**                                                                                                  
 901      * Update an item to the database in a specified container.                                          
 902      */                                                                                                  
 903     static void updateItemInDatabase(Context context, final ItemInfo item) {                             
 904         final ContentValues values = new ContentValues();                                                
 905         item.onAddToDatabase(context, values);                                                           
 906         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 907     }                                                                                                    
 908                                                                                                          
 909     /**                                                                                                  
 910      * Returns true if the shortcuts already exists in the database.                                     
 911      * we identify a shortcut by its title and intent.                                                   
 912      */                                                                                                  
 913     static boolean shortcutExists(Context context, String title, Intent intent,                          
 914             UserHandleCompat user) {                                                                     
 915         final ContentResolver cr = context.getContentResolver();                                         
 916         final Intent intentWithPkg, intentWithoutPkg;                                                    
 917                                                                                                          
 918         if (intent.getComponent() != null) {                                                             
 919             // If component is not null, an intent with null package will produce                        
 920             // the same result and should also be a match.                                               
 921             if (intent.getPackage() != null) {                                                           
 922                 intentWithPkg = intent;                                                                  
 923                 intentWithoutPkg = new Intent(intent).setPackage(null);                                  
 924             } else {                                                                                     
 925                 intentWithPkg = new Intent(intent).setPackage(                                           
 926                         intent.getComponent().getPackageName());                                         
 927                 intentWithoutPkg = intent;                                                               
 928             }                                                                                            
 929         } else {                                                                                         
 930             intentWithPkg = intent;                                                                      
 931             intentWithoutPkg = intent;                                                                   
 932         }                                                                                                
 933         String userSerial = Long.toString(UserManagerCompat.getInstance(context)                         
 934                 .getSerialNumberForUser(user));                                                          
 935         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 936             new String[] { "title", "intent", "profileId" },                                             
 937             "title=? and (intent=? or intent=?) and profileId=?",                                        
 938             new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },       
 939             null);                                                                                       
 940         try {                                                                                            
 941             return c.moveToFirst();                                                                      
 942         } finally {                                                                                      
 943             c.close();                                                                                   
 944         }                                                                                                
 945     }                                                                                                    
 946                                                                                                          
 947     /**                                                                                                  
 948      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 949      */                                                                                                  
 950     FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {            
 951         final ContentResolver cr = context.getContentResolver();                                         
 952         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 953                 "_id=? and (itemType=? or itemType=?)",                                                  
 954                 new String[] { String.valueOf(id),                                                       
 955                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 956                                                                                                          
 957         try {                                                                                            
 958             if (c.moveToFirst()) {                                                                       
 959                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 960                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 961                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 962                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 963                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 964                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 965                                                                                                          
 966                 FolderInfo folderInfo = null;                                                            
 967                 switch (c.getInt(itemTypeIndex)) {                                                       
 968                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 969                         folderInfo = findOrMakeFolder(folderList, id);                                   
 970                         break;                                                                           
 971                 }                                                                                        
 972                                                                                                          
 973                 folderInfo.title = c.getString(titleIndex);                                              
 974                 folderInfo.id = id;                                                                      
 975                 folderInfo.container = c.getInt(containerIndex);                                         
 976                 folderInfo.screenId = c.getInt(screenIndex);                                             
 977                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
 978                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
 979                                                                                                          
 980                 return folderInfo;                                                                       
 981             }                                                                                            
 982         } finally {                                                                                      
 983             c.close();                                                                                   
 984         }                                                                                                
 985                                                                                                          
 986         return null;                                                                                     
 987     }                                                                                                    
 988                                                                                                          
 989     /**                                                                                                  
 990      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
 991      * cellY fields of the item. Also assigns an ID to the item.                                         
 992      */                                                                                                  
 993     static void addItemToDatabase(Context context, final ItemInfo item, final long container,            
 994             final long screenId, final int cellX, final int cellY, final boolean notify) {               
 995         item.container = container;                                                                      
 996         item.cellX = cellX;                                                                              
 997         item.cellY = cellY;                                                                              
 998         // We store hotseat items in canonical form which is this orientation invariant position         
 999         // in the hotseat                                                                                
1000         if (context instanceof Launcher && screenId < 0 &&                                               
1001                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
1002             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1003         } else {                                                                                         
1004             item.screenId = screenId;                                                                    
1005         }                                                                                                
1006                                                                                                          
1007         final ContentValues values = new ContentValues();                                                
1008         final ContentResolver cr = context.getContentResolver();                                         
1009         item.onAddToDatabase(context, values);                                                           
1010                                                                                                          
1011         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1012         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1013                                                                                                          
1014         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
1015         Runnable r = new Runnable() {                                                                    
1016             public void run() {                                                                          
1017                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                              
1018                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                 
1019                                                                                                          
1020                 // Lock on mBgLock *after* the db operation                                              
1021                 synchronized (sBgLock) {                                                                 
1022                     checkItemInfoLocked(item.id, item, stackTrace);                                      
1023                     sBgItemsIdMap.put(item.id, item);                                                    
1024                     switch (item.itemType) {                                                             
1025                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1026                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1027                             // Fall through                                                              
1028                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1029                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1030                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1031                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1032                                 sBgWorkspaceItems.add(item);                                             
1033                             } else {                                                                     
1034                                 if (!sBgFolders.containsKey(item.container)) {                           
1035                                     // Adding an item to a folder that doesn't exist.                    
1036                                     String msg = "adding item: " + item + " to a folder that " +         
1037                                             " doesn't exist";                                            
1038                                     Log.e(TAG, msg);                                                     
1039                                 }                                                                        
1040                             }                                                                            
1041                             break;                                                                       
1042                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1043                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1044                             break;                                                                       
1045                     }                                                                                    
1046                 }                                                                                        
1047             }                                                                                            
1048         };                                                                                               
1049         runOnWorkerThread(r);                                                                            
1050     }                                                                                                    
1051                                                                                                          
1052     /**                                                                                                  
1053      * Creates a new unique child id, for a given cell span across all layouts.                          
1054      */                                                                                                  
1055     static int getCellLayoutChildId(                                                                     
1056             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1057         return (((int) container & 0xFF) << 24)                                                          
1058                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1059     }                                                                                                    
1060                                                                                                          
1061     private static ArrayList<ItemInfo> getItemsByPackageName(                                            
1062             final String pn, final UserHandleCompat user) {                                              
1063         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
1064             @Override                                                                                    
1065             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
1066                 return cn.getPackageName().equals(pn) && info.user.equals(user);                         
1067             }                                                                                            
1068         };                                                                                               
1069         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
1070     }                                                                                                    
1071                                                                                                          
1072     /**                                                                                                  
1073      * Removes all the items from the database corresponding to the specified package.                   
1074      */                                                                                                  
1075     static void deletePackageFromDatabase(Context context, final String pn,                              
1076             final UserHandleCompat user) {                                                               
1077         deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                               
1078     }                                                                                                    
1079                                                                                                          
1080     /**                                                                                                  
1081      * Removes the specified item from the database                                                      
1082      * @param context                                                                                    
1083      * @param item                                                                                       
1084      */                                                                                                  
1085     static void deleteItemFromDatabase(Context context, final ItemInfo item) {                           
1086         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1087         items.add(item);                                                                                 
1088         deleteItemsFromDatabase(context, items);                                                         
1089     }                                                                                                    
1090                                                                                                          
1091     /**                                                                                                  
1092      * Removes the specified items from the database                                                     
1093      * @param context                                                                                    
1094      * @param item                                                                                       
1095      */                                                                                                  
1096     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {    
1097         final ContentResolver cr = context.getContentResolver();                                         
1098                                                                                                          
1099         Runnable r = new Runnable() {                                                                    
1100             public void run() {                                                                          
1101                 for (ItemInfo item : items) {                                                            
1102                     final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);            
1103                     cr.delete(uri, null, null);                                                          
1104                                                                                                          
1105                     // Lock on mBgLock *after* the db operation                                          
1106                     synchronized (sBgLock) {                                                             
1107                         switch (item.itemType) {                                                         
1108                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
1109                                 sBgFolders.remove(item.id);                                              
1110                                 for (ItemInfo info: sBgItemsIdMap.values()) {                            
1111                                     if (info.container == item.id) {                                     
1112                                         // We are deleting a folder which still contains items that      
1113                                         // think they are contained by that folder.                      
1114                                         String msg = "deleting a folder (" + item + ") which still " +   
1115                                                 "contains items (" + info + ")";                         
1116                                         Log.e(TAG, msg);                                                 
1117                                     }                                                                    
1118                                 }                                                                        
1119                                 sBgWorkspaceItems.remove(item);                                          
1120                                 break;                                                                   
1121                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1122                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1123                                 sBgWorkspaceItems.remove(item);                                          
1124                                 break;                                                                   
1125                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
1126                                 sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                      
1127                                 break;                                                                   
1128                         }                                                                                
1129                         sBgItemsIdMap.remove(item.id);                                                   
1130                     }                                                                                    
1131                 }                                                                                        
1132             }                                                                                            
1133         };                                                                                               
1134         runOnWorkerThread(r);                                                                            
1135     }                                                                                                    
1136                                                                                                          
1137     /**                                                                                                  
1138      * Update the order of the workspace screens in the database. The array list contains                
1139      * a list of screen ids in the order that they should appear.                                        
1140      */                                                                                                  
1141     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1142         // Log to disk                                                                                   
1143         Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                       
1144         Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);        
1145                                                                                                          
1146         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1147         final ContentResolver cr = context.getContentResolver();                                         
1148         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1149                                                                                                          
1150         // Remove any negative screen ids -- these aren't persisted                                      
1151         Iterator<Long> iter = screensCopy.iterator();                                                    
1152         while (iter.hasNext()) {                                                                         
1153             long id = iter.next();                                                                       
1154             if (id < 0) {                                                                                
1155                 iter.remove();                                                                           
1156             }                                                                                            
1157         }                                                                                                
1158                                                                                                          
1159         Runnable r = new Runnable() {                                                                    
1160             @Override                                                                                    
1161             public void run() {                                                                          
1162                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
1163                 // Clear the table                                                                       
1164                 ops.add(ContentProviderOperation.newDelete(uri).build());                                
1165                 int count = screensCopy.size();                                                          
1166                 for (int i = 0; i < count; i++) {                                                        
1167                     ContentValues v = new ContentValues();                                               
1168                     long screenId = screensCopy.get(i);                                                  
1169                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1170                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1171                     ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());              
1172                 }                                                                                        
1173                                                                                                          
1174                 try {                                                                                    
1175                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
1176                 } catch (Exception ex) {                                                                 
1177                     throw new RuntimeException(ex);                                                      
1178                 }                                                                                        
1179                                                                                                          
1180                 synchronized (sBgLock) {                                                                 
1181                     sBgWorkspaceScreens.clear();                                                         
1182                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1183                 }                                                                                        
1184             }                                                                                            
1185         };                                                                                               
1186         runOnWorkerThread(r);                                                                            
1187     }                                                                                                    
1188                                                                                                          
1189     /**                                                                                                  
1190      * Remove the contents of the specified folder from the database                                     
1191      */                                                                                                  
1192     static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {               
1193         final ContentResolver cr = context.getContentResolver();                                         
1194                                                                                                          
1195         Runnable r = new Runnable() {                                                                    
1196             public void run() {                                                                          
1197                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);         
1198                 // Lock on mBgLock *after* the db operation                                              
1199                 synchronized (sBgLock) {                                                                 
1200                     sBgItemsIdMap.remove(info.id);                                                       
1201                     sBgFolders.remove(info.id);                                                          
1202                     sBgWorkspaceItems.remove(info);                                                      
1203                 }                                                                                        
1204                                                                                                          
1205                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                        
1206                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1207                 // Lock on mBgLock *after* the db operation                                              
1208                 synchronized (sBgLock) {                                                                 
1209                     for (ItemInfo childInfo : info.contents) {                                           
1210                         sBgItemsIdMap.remove(childInfo.id);                                              
1211                     }                                                                                    
1212                 }                                                                                        
1213             }                                                                                            
1214         };                                                                                               
1215         runOnWorkerThread(r);                                                                            
1216     }                                                                                                    
1217                                                                                                          
1218     /**                                                                                                  
1219      * Set this as the current Launcher activity object for the loader.                                  
1220      */                                                                                                  
1221     public void initialize(Callbacks callbacks) {                                                        
1222         synchronized (mLock) {                                                                           
1223             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1224         }                                                                                                
1225     }                                                                                                    
1226                                                                                                          
1227     @Override                                                                                            
1228     public void onPackageChanged(String packageName, UserHandleCompat user) {                            
1229         int op = PackageUpdatedTask.OP_UPDATE;                                                           
1230         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1231                 user));                                                                                  
1232     }                                                                                                    
1233                                                                                                          
1234     @Override                                                                                            
1235     public void onPackageRemoved(String packageName, UserHandleCompat user) {                            
1236         int op = PackageUpdatedTask.OP_REMOVE;                                                           
1237         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1238                 user));                                                                                  
1239     }                                                                                                    
1240                                                                                                          
1241     @Override                                                                                            
1242     public void onPackageAdded(String packageName, UserHandleCompat user) {                              
1243         int op = PackageUpdatedTask.OP_ADD;                                                              
1244         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1245                 user));                                                                                  
1246     }                                                                                                    
1247                                                                                                          
1248     @Override                                                                                            
1249     public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                        
1250             boolean replacing) {                                                                         
1251         if (!replacing) {                                                                                
1252             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,        
1253                     user));                                                                              
1254             if (mAppsCanBeOnRemoveableStorage) {                                                         
1255                 // Only rebind if we support removable storage. It catches the                           
1256                 // case where                                                                            
1257                 // apps on the external sd card need to be reloaded                                      
1258                 startLoaderFromBackground();                                                             
1259             }                                                                                            
1260         } else {                                                                                         
1261             // If we are replacing then just update the packages in the list                             
1262             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                   
1263                     packageNames, user));                                                                
1264         }                                                                                                
1265     }                                                                                                    
1266                                                                                                          
1267     @Override                                                                                            
1268     public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                      
1269             boolean replacing) {                                                                         
1270         if (!replacing) {                                                                                
1271             enqueuePackageUpdated(new PackageUpdatedTask(                                                
1272                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                     
1273                     user));                                                                              
1274         }                                                                                                
1275     }                                                                                                    
1276                                                                                                          
1277     /**                                                                                                  
1278      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1279      * ACTION_PACKAGE_CHANGED.                                                                           
1280      */                                                                                                  
1281     @Override                                                                                            
1282     public void onReceive(Context context, Intent intent) {                                              
1283         if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                    
1284                                                                                                          
1285         final String action = intent.getAction();                                                        
1286         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                               
1287             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1288             forceReload();                                                                               
1289         } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                 
1290              // Check if configuration change was an mcc/mnc change which would affect app resources     
1291              // and we would need to clear out the labels in all apps/workspace. Same handling as        
1292              // above for ACTION_LOCALE_CHANGED                                                          
1293              Configuration currentConfig = context.getResources().getConfiguration();                    
1294              if (mPreviousConfigMcc != currentConfig.mcc) {                                              
1295                    Log.d(TAG, "Reload apps on config change. curr_mcc:"                                  
1296                        + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                          
1297                    forceReload();                                                                        
1298              }                                                                                           
1299              // Update previousConfig                                                                    
1300              mPreviousConfigMcc = currentConfig.mcc;                                                     
1301         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1302                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1303             Callbacks callbacks = getCallback();                                                         
1304             if (callbacks != null) {                                                                     
1305                 callbacks.bindSearchablesChanged();                                                      
1306             }                                                                                            
1307         }                                                                                                
1308     }                                                                                                    
1309                                                                                                          
1310     void forceReload() {                                                                                 
1311         resetLoadedState(true, true);                                                                    
1312                                                                                                          
1313         // Do this here because if the launcher activity is running it will be restarted.                
1314         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1315         // to reload.                                                                                    
1316         startLoaderFromBackground();                                                                     
1317     }                                                                                                    
1318                                                                                                          
1319     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1320         synchronized (mLock) {                                                                           
1321             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1322             // mWorkspaceLoaded to true later                                                            
1323             stopLoaderLocked();                                                                          
1324             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1325             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1326         }                                                                                                
1327     }                                                                                                    
1328                                                                                                          
1329     /**                                                                                                  
1330      * When the launcher is in the background, it's possible for it to miss paired                       
1331      * configuration changes.  So whenever we trigger the loader from the background                     
1332      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1333      * of doing it now.                                                                                  
1334      */                                                                                                  
1335     public void startLoaderFromBackground() {                                                            
1336         boolean runLoader = false;                                                                       
1337         Callbacks callbacks = getCallback();                                                             
1338         if (callbacks != null) {                                                                         
1339             // Only actually run the loader if they're not paused.                                       
1340             if (!callbacks.setLoadOnResume()) {                                                          
1341                 runLoader = true;                                                                        
1342             }                                                                                            
1343         }                                                                                                
1344         if (runLoader) {                                                                                 
1345             startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                          
1346         }                                                                                                
1347     }                                                                                                    
1348                                                                                                          
1349     // If there is already a loader task running, tell it to stop.                                       
1350     // returns true if isLaunching() was true on the old task                                            
1351     private boolean stopLoaderLocked() {                                                                 
1352         boolean isLaunching = false;                                                                     
1353         LoaderTask oldTask = mLoaderTask;                                                                
1354         if (oldTask != null) {                                                                           
1355             if (oldTask.isLaunching()) {                                                                 
1356                 isLaunching = true;                                                                      
1357             }                                                                                            
1358             oldTask.stopLocked();                                                                        
1359         }                                                                                                
1360         return isLaunching;                                                                              
1361     }                                                                                                    
1362                                                                                                          
1363     public boolean isCurrentCallbacks(Callbacks callbacks) {                                             
1364         return (mCallbacks != null && mCallbacks.get() == callbacks);                                    
1365     }                                                                                                    
1366                                                                                                          
1367     public void startLoader(boolean isLaunching, int synchronousBindPage) {                              
1368         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                 
1369     }                                                                                                    
1370                                                                                                          
1371     public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {               
1372         synchronized (mLock) {                                                                           
1373             if (DEBUG_LOADERS) {                                                                         
1374                 Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                    
1375             }                                                                                            
1376                                                                                                          
1377             // Clear any deferred bind-runnables from the synchronized load process                      
1378             // We must do this before any loading/binding is scheduled below.                            
1379             synchronized (mDeferredBindRunnables) {                                                      
1380                 mDeferredBindRunnables.clear();                                                          
1381             }                                                                                            
1382                                                                                                          
1383             // Don't bother to start the thread if we know it's not going to do anything                 
1384             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1385                 // If there is already one running, tell it to stop.                                     
1386                 // also, don't downgrade isLaunching if we're already running                            
1387                 isLaunching = isLaunching || stopLoaderLocked();                                         
1388                 mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                 
1389                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1390                         && mAllAppsLoaded && mWorkspaceLoaded) {                                         
1391                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1392                 } else {                                                                                 
1393                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1394                     sWorker.post(mLoaderTask);                                                           
1395                 }                                                                                        
1396             }                                                                                            
1397         }                                                                                                
1398     }                                                                                                    
1399                                                                                                          
1400     void bindRemainingSynchronousPages() {                                                               
1401         // Post the remaining side pages to be loaded                                                    
1402         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1403             Runnable[] deferredBindRunnables = null;                                                     
1404             synchronized (mDeferredBindRunnables) {                                                      
1405                 deferredBindRunnables = mDeferredBindRunnables.toArray(                                  
1406                         new Runnable[mDeferredBindRunnables.size()]);                                    
1407                 mDeferredBindRunnables.clear();                                                          
1408             }                                                                                            
1409             for (final Runnable r : deferredBindRunnables) {                                             
1410                 mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                          
1411             }                                                                                            
1412         }                                                                                                
1413     }                                                                                                    
1414                                                                                                          
1415     public void stopLoader() {                                                                           
1416         synchronized (mLock) {                                                                           
1417             if (mLoaderTask != null) {                                                                   
1418                 mLoaderTask.stopLocked();                                                                
1419             }                                                                                            
1420         }                                                                                                
1421     }                                                                                                    
1422                                                                                                          
1423     /**                                                                                                  
1424      * Loads the workspace screen ids in an ordered list.                                                
1425      */                                                                                                  
1426     private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                             
1427         final ContentResolver contentResolver = context.getContentResolver();                            
1428         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1429                                                                                                          
1430         // Get screens ordered by rank.                                                                  
1431         final Cursor sc = contentResolver.query(screensUri, null, null, null,                            
1432                 LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                          
1433         ArrayList<Long> screenIds = new ArrayList<Long>();                                               
1434         try {                                                                                            
1435             final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);         
1436             while (sc.moveToNext()) {                                                                    
1437                 try {                                                                                    
1438                     screenIds.add(sc.getLong(idIndex));                                                  
1439                 } catch (Exception e) {                                                                  
1440                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                         
1441                             + " - invalid screens: " + e, true);                                         
1442                 }                                                                                        
1443             }                                                                                            
1444         } finally {                                                                                      
1445             sc.close();                                                                                  
1446         }                                                                                                
1447         return screenIds;                                                                                
1448     }                                                                                                    
1449                                                                                                          
1450     public boolean isAllAppsLoaded() {                                                                   
1451         return mAllAppsLoaded;                                                                           
1452     }                                                                                                    
1453                                                                                                          
1454     boolean isLoadingWorkspace() {                                                                       
1455         synchronized (mLock) {                                                                           
1456             if (mLoaderTask != null) {                                                                   
1457                 return mLoaderTask.isLoadingWorkspace();                                                 
1458             }                                                                                            
1459         }                                                                                                
1460         return false;                                                                                    
1461     }                                                                                                    
1462                                                                                                          
1463     /**                                                                                                  
1464      * Runnable for the thread that loads the contents of the launcher:                                  
1465      *   - workspace icons                                                                               
1466      *   - widgets                                                                                       
1467      *   - all apps icons                                                                                
1468      */                                                                                                  
1469     private class LoaderTask implements Runnable {                                                       
1470         private Context mContext;                                                                        
1471         private boolean mIsLaunching;                                                                    
1472         private boolean mIsLoadingAndBindingWorkspace;                                                   
1473         private boolean mStopped;                                                                        
1474         private boolean mLoadAndBindStepFinished;                                                        
1475         private int mFlags;                                                                              
1476                                                                                                          
1477         LoaderTask(Context context, boolean isLaunching, int flags) {                                    
1478             mContext = context;                                                                          
1479             mIsLaunching = isLaunching;                                                                  
1480             mFlags = flags;                                                                              
1481         }                                                                                                
1482                                                                                                          
1483         boolean isLaunching() {                                                                          
1484             return mIsLaunching;                                                                         
1485         }                                                                                                
1486                                                                                                          
1487         boolean isLoadingWorkspace() {                                                                   
1488             return mIsLoadingAndBindingWorkspace;                                                        
1489         }                                                                                                
1490                                                                                                          
1491         private void loadAndBindWorkspace() {                                                            
1492             mIsLoadingAndBindingWorkspace = true;                                                        
1493                                                                                                          
1494             // Load the workspace                                                                        
1495             if (DEBUG_LOADERS) {                                                                         
1496                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1497             }                                                                                            
1498                                                                                                          
1499             if (!mWorkspaceLoaded) {                                                                     
1500                 loadWorkspace();                                                                         
1501                 synchronized (LoaderTask.this) {                                                         
1502                     if (mStopped) {                                                                      
1503                         return;                                                                          
1504                     }                                                                                    
1505                     mWorkspaceLoaded = true;                                                             
1506                 }                                                                                        
1507             }                                                                                            
1508                                                                                                          
1509             // Bind the workspace                                                                        
1510             bindWorkspace(-1);                                                                           
1511         }                                                                                                
1512                                                                                                          
1513         private void waitForIdle() {                                                                     
1514             // Wait until the either we're stopped or the other threads are done.                        
1515             // This way we don't start loading all apps until the workspace has settled                  
1516             // down.                                                                                     
1517             synchronized (LoaderTask.this) {                                                             
1518                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1519                                                                                                          
1520                 mHandler.postIdle(new Runnable() {                                                       
1521                         public void run() {                                                              
1522                             synchronized (LoaderTask.this) {                                             
1523                                 mLoadAndBindStepFinished = true;                                         
1524                                 if (DEBUG_LOADERS) {                                                     
1525                                     Log.d(TAG, "done with previous binding step");                       
1526                                 }                                                                        
1527                                 LoaderTask.this.notify();                                                
1528                             }                                                                            
1529                         }                                                                                
1530                     });                                                                                  
1531                                                                                                          
1532                 while (!mStopped && !mLoadAndBindStepFinished) {                                         
1533                     try {                                                                                
1534                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1535                         // wait no longer than 1sec at a time                                            
1536                         this.wait(1000);                                                                 
1537                     } catch (InterruptedException ex) {                                                  
1538                         // Ignore                                                                        
1539                     }                                                                                    
1540                 }                                                                                        
1541                 if (DEBUG_LOADERS) {                                                                     
1542                     Log.d(TAG, "waited "                                                                 
1543                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1544                             + "ms for previous step to finish binding");                                 
1545                 }                                                                                        
1546             }                                                                                            
1547         }                                                                                                
1548                                                                                                          
1549         void runBindSynchronousPage(int synchronousBindPage) {                                           
1550             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1551                 // Ensure that we have a valid page index to load synchronously                          
1552                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1553                         "valid page index");                                                             
1554             }                                                                                            
1555             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1556                 // Ensure that we don't try and bind a specified page when the pages have not been       
1557                 // loaded already (we should load everything asynchronously in that case)                
1558                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1559             }                                                                                            
1560             synchronized (mLock) {                                                                       
1561                 if (mIsLoaderTaskRunning) {                                                              
1562                     // Ensure that we are never running the background loading at this point since       
1563                     // we also touch the background collections                                          
1564                     throw new RuntimeException("Error! Background loading is already running");          
1565                 }                                                                                        
1566             }                                                                                            
1567                                                                                                          
1568             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1569             //      data structures, we can't allow any other thread to touch that data, but because     
1570             //      this call is synchronous, we can get away with not locking).                         
1571                                                                                                          
1572             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1573             // operations from the previous activity.  We need to ensure that all queued operations      
1574             // are executed before any synchronous binding work is done.                                 
1575             mHandler.flush();                                                                            
1576                                                                                                          
1577             // Divide the set of loaded items into those that we are binding synchronously, and          
1578             // everything else that is to be bound normally (asynchronously).                            
1579             bindWorkspace(synchronousBindPage);                                                          
1580             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1581             //      arise from that.                                                                     
1582             onlyBindAllApps();                                                                           
1583         }                                                                                                
1584                                                                                                          
1585         public void run() {                                                                              
1586             synchronized (mLock) {                                                                       
1587                 mIsLoaderTaskRunning = true;                                                             
1588             }                                                                                            
1589             // Optimize for end-user experience: if the Launcher is up and // running with the           
1590             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1591             // workspace first (default).                                                                
1592             keep_running: {                                                                              
1593                 // Elevate priority when Home launches for the first time to avoid                       
1594                 // starving at boot time. Staring at a blank home is not cool.                           
1595                 synchronized (mLock) {                                                                   
1596                     if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                        
1597                             (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                  
1598                     android.os.Process.setThreadPriority(mIsLaunching                                    
1599                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);     
1600                 }                                                                                        
1601                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1602                 loadAndBindWorkspace();                                                                  
1603                                                                                                          
1604                 if (mStopped) {                                                                          
1605                     break keep_running;                                                                  
1606                 }                                                                                        
1607                                                                                                          
1608                 // Whew! Hard work done.  Slow us down, and wait until the UI thread has                 
1609                 // settled down.                                                                         
1610                 synchronized (mLock) {                                                                   
1611                     if (mIsLaunching) {                                                                  
1612                         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");          
1613                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        
1614                     }                                                                                    
1615                 }                                                                                        
1616                 waitForIdle();                                                                           
1617                                                                                                          
1618                 // second step                                                                           
1619                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1620                 loadAndBindAllApps();                                                                    
1621                                                                                                          
1622                 // Restore the default thread priority after we are done loading items                   
1623                 synchronized (mLock) {                                                                   
1624                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1625                 }                                                                                        
1626             }                                                                                            
1627                                                                                                          
1628 <<<<<<< GitAnalyzerPlus_ours                                                                             
1629             if (LauncherAppState.isDisableAllApps()) {                                                   
1630                 // Ensure that all the applications that are in the system are                           
1631                 // represented on the home screen.                                                       
1632                 verifyApplications();                                                                    
1633 ||||||| GitAnalyzerPlus_base                                                                             
1634                 // second step                                                                           
1635                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1636                 loadAndBindAllApps();                                                                    
1637                                                                                                          
1638                 // Restore the default thread priority after we are done loading items                   
1639                 synchronized (mLock) {                                                                   
1640                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1641                 }                                                                                        
1642             }                                                                                            
1643                                                                                                          
1644             // Update the saved icons if necessary                                                       
1645             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1646             synchronized (sBgLock) {                                                                     
1647                 for (Object key : sBgDbIconCache.keySet()) {                                             
1648                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1649                 }                                                                                        
1650                 sBgDbIconCache.clear();                                                                  
1651 =======                                                                                                  
1652             // Update the saved icons if necessary                                                       
1653             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1654             synchronized (sBgLock) {                                                                     
1655                 for (Object key : sBgDbIconCache.keySet()) {                                             
1656                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1657                 }                                                                                        
1658                 sBgDbIconCache.clear();                                                                  
1659 >>>>>>> GitAnalyzerPlus_theirs                                                                           
1660             }                                                                                            
1661                                                                                                          
1662             // Clear out this reference, otherwise we end up holding it until all of the                 
1663             // callback runnables are done.                                                              
1664             mContext = null;                                                                             
1665                                                                                                          
1666             synchronized (mLock) {                                                                       
1667                 // If we are still the last one to be scheduled, remove ourselves.                       
1668                 if (mLoaderTask == this) {                                                               
1669                     mLoaderTask = null;                                                                  
1670                 }                                                                                        
1671                 mIsLoaderTaskRunning = false;                                                            
1672             }                                                                                            
1673         }                                                                                                
1674                                                                                                          
1675         public void stopLocked() {                                                                       
1676             synchronized (LoaderTask.this) {                                                             
1677                 mStopped = true;                                                                         
1678                 this.notify();                                                                           
1679             }                                                                                            
1680         }                                                                                                
1681                                                                                                          
1682         /**                                                                                              
1683          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1684          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1685          * object that was around when the deferred message was scheduled, and if there's                
1686          * a new Callbacks object around then also return null.  This will save us from                  
1687          * calling onto it with data that will be ignored.                                               
1688          */                                                                                              
1689         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1690             synchronized (mLock) {                                                                       
1691                 if (mStopped) {                                                                          
1692                     return null;                                                                         
1693                 }                                                                                        
1694                                                                                                          
1695                 if (mCallbacks == null) {                                                                
1696                     return null;                                                                         
1697                 }                                                                                        
1698                                                                                                          
1699                 final Callbacks callbacks = mCallbacks.get();                                            
1700                 if (callbacks != oldCallbacks) {                                                         
1701                     return null;                                                                         
1702                 }                                                                                        
1703                 if (callbacks == null) {                                                                 
1704                     Log.w(TAG, "no mCallbacks");                                                         
1705                     return null;                                                                         
1706                 }                                                                                        
1707                                                                                                          
1708                 return callbacks;                                                                        
1709             }                                                                                            
1710         }                                                                                                
1711                                                                                                          
1712         // check & update map of what's occupied; used to discard overlapping/invalid items              
1713         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {        
1714             LauncherAppState app = LauncherAppState.getInstance();                                       
1715             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1716             final int countX = (int) grid.numColumns;                                                    
1717             final int countY = (int) grid.numRows;                                                       
1718                                                                                                          
1719             long containerIndex = item.screenId;                                                         
1720             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1721                 // Return early if we detect that an item is under the hotseat button                    
1722                 if (mCallbacks == null ||                                                                
1723                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1724                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1725                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1726                             + item.cellY + ") occupied by all apps");                                    
1727                     return false;                                                                        
1728                 }                                                                                        
1729                                                                                                          
1730                 final ItemInfo[][] hotseatItems =                                                        
1731                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1732                                                                                                          
1733                 if (item.screenId >= grid.numHotseatIcons) {                                             
1734                     Log.e(TAG, "Error loading shortcut " + item                                          
1735                             + " into hotseat position " + item.screenId                                  
1736                             + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)            
1737                             + ")");                                                                      
1738                     return false;                                                                        
1739                 }                                                                                        
1740                                                                                                          
1741                 if (hotseatItems != null) {                                                              
1742                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1743                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1744                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1745                                 + item.cellY + ") occupied by "                                          
1746                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1747                                 [(int) item.screenId][0]);                                               
1748                             return false;                                                                
1749                     } else {                                                                             
1750                         hotseatItems[(int) item.screenId][0] = item;                                     
1751                         return true;                                                                     
1752                     }                                                                                    
1753                 } else {                                                                                 
1754                     final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];              
1755                     items[(int) item.screenId][0] = item;                                                
1756                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1757                     return true;                                                                         
1758                 }                                                                                        
1759             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1760                 // Skip further checking if it is not the hotseat or workspace container                 
1761                 return true;                                                                             
1762             }                                                                                            
1763                                                                                                          
1764             if (!occupied.containsKey(item.screenId)) {                                                  
1765                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1766                 occupied.put(item.screenId, items);                                                      
1767             }                                                                                            
1768                                                                                                          
1769             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1770             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1771                     item.cellX < 0 || item.cellY < 0 ||                                                  
1772                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1773                 Log.e(TAG, "Error loading shortcut " + item                                              
1774                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1775                         + item.cellX + "," + item.cellY                                                  
1776                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1777                 return false;                                                                            
1778             }                                                                                            
1779                                                                                                          
1780             // Check if any workspace icons overlap with each other                                      
1781             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1782                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1783                     if (screens[x][y] != null) {                                                         
1784                         Log.e(TAG, "Error loading shortcut " + item                                      
1785                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1786                             + x + "," + y                                                                
1787                             + ") occupied by "                                                           
1788                             + screens[x][y]);                                                            
1789                         return false;                                                                    
1790                     }                                                                                    
1791                 }                                                                                        
1792             }                                                                                            
1793             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1794                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1795                     screens[x][y] = item;                                                                
1796                 }                                                                                        
1797             }                                                                                            
1798                                                                                                          
1799             return true;                                                                                 
1800         }                                                                                                
1801                                                                                                          
1802         /** Clears all the sBg data structures */                                                        
1803         private void clearSBgDataStructures() {                                                          
1804             synchronized (sBgLock) {                                                                     
1805                 sBgWorkspaceItems.clear();                                                               
1806                 sBgAppWidgets.clear();                                                                   
1807                 sBgFolders.clear();                                                                      
1808                 sBgItemsIdMap.clear();                                                                   
1809                 sBgWorkspaceScreens.clear();                                                             
1810             }                                                                                            
1811         }                                                                                                
1812                                                                                                          
1813         private void loadWorkspace() {                                                                   
1814             // Log to disk                                                                               
1815             Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                
1816                                                                                                          
1817             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                               
1818                                                                                                          
1819             final Context context = mContext;                                                            
1820             final ContentResolver contentResolver = context.getContentResolver();                        
1821             final PackageManager manager = context.getPackageManager();                                  
1822             final boolean isSafeMode = manager.isSafeMode();                                             
1823             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);             
1824             final boolean isSdCardReady = context.registerReceiver(null,                                 
1825                     new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                             
1826                                                                                                          
1827             LauncherAppState app = LauncherAppState.getInstance();                                       
1828             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1829             int countX = (int) grid.numColumns;                                                          
1830             int countY = (int) grid.numRows;                                                             
1831                                                                                                          
1832             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1833                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1834                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1835             }                                                                                            
1836                                                                                                          
1837             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1838                 // append the user's Launcher2 shortcuts                                                 
1839                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1840                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1841             } else {                                                                                     
1842                 // Make sure the default workspace is loaded                                             
1843                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1844                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                
1845             }                                                                                            
1846                                                                                                          
1847             synchronized (sBgLock) {                                                                     
1848                 clearSBgDataStructures();                                                                
1849                 final HashSet<String> installingPkgs = PackageInstallerCompat                            
1850                         .getInstance(mContext).updateAndGetActiveSessionCache();                         
1851                                                                                                          
1852                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1853                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1854                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;           
1855                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                       
1856                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1857                                                                                                          
1858                 // +1 for the hotseat (it can be larger than the workspace)                              
1859                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1860                 // before any earlier duplicates)                                                        
1861                 final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();          
1862                                                                                                          
1863                 try {                                                                                    
1864                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1865                     final int intentIndex = c.getColumnIndexOrThrow                                      
1866                             (LauncherSettings.Favorites.INTENT);                                         
1867                     final int titleIndex = c.getColumnIndexOrThrow                                       
1868                             (LauncherSettings.Favorites.TITLE);                                          
1869                     final int iconTypeIndex = c.getColumnIndexOrThrow(                                   
1870                             LauncherSettings.Favorites.ICON_TYPE);                                       
1871                     final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);      
1872                     final int iconPackageIndex = c.getColumnIndexOrThrow(                                
1873                             LauncherSettings.Favorites.ICON_PACKAGE);                                    
1874                     final int iconResourceIndex = c.getColumnIndexOrThrow(                               
1875                             LauncherSettings.Favorites.ICON_RESOURCE);                                   
1876                     final int containerIndex = c.getColumnIndexOrThrow(                                  
1877                             LauncherSettings.Favorites.CONTAINER);                                       
1878                     final int itemTypeIndex = c.getColumnIndexOrThrow(                                   
1879                             LauncherSettings.Favorites.ITEM_TYPE);                                       
1880                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                
1881                             LauncherSettings.Favorites.APPWIDGET_ID);                                    
1882                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                          
1883                             LauncherSettings.Favorites.APPWIDGET_PROVIDER);                              
1884                     final int screenIndex = c.getColumnIndexOrThrow(                                     
1885                             LauncherSettings.Favorites.SCREEN);                                          
1886                     final int cellXIndex = c.getColumnIndexOrThrow                                       
1887                             (LauncherSettings.Favorites.CELLX);                                          
1888                     final int cellYIndex = c.getColumnIndexOrThrow                                       
1889                             (LauncherSettings.Favorites.CELLY);                                          
1890                     final int spanXIndex = c.getColumnIndexOrThrow                                       
1891                             (LauncherSettings.Favorites.SPANX);                                          
1892                     final int spanYIndex = c.getColumnIndexOrThrow(                                      
1893                             LauncherSettings.Favorites.SPANY);                                           
1894                     final int rankIndex = c.getColumnIndexOrThrow(                                       
1895                             LauncherSettings.Favorites.RANK);                                            
1896                     final int restoredIndex = c.getColumnIndexOrThrow(                                   
1897                             LauncherSettings.Favorites.RESTORED);                                        
1898                     final int profileIdIndex = c.getColumnIndexOrThrow(                                  
1899                             LauncherSettings.Favorites.PROFILE_ID);                                      
1900                     //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);      
1901                     //final int displayModeIndex = c.getColumnIndexOrThrow(                              
1902                     //        LauncherSettings.Favorites.DISPLAY_MODE);                                  
1903                                                                                                          
1904                     ShortcutInfo info;                                                                   
1905                     String intentDescription;                                                            
1906                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1907                     int container;                                                                       
1908                     long id;                                                                             
1909                     Intent intent;                                                                       
1910                     UserHandleCompat user;                                                               
1911                                                                                                          
1912                     while (!mStopped && c.moveToNext()) {                                                
1913                         try {                                                                            
1914                             int itemType = c.getInt(itemTypeIndex);                                      
1915                             boolean restored = 0 != c.getInt(restoredIndex);                             
1916                             boolean allowMissingTarget = false;                                          
1917                                                                                                          
1918                             switch (itemType) {                                                          
1919                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1920                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1921                                 id = c.getLong(idIndex);                                                 
1922                                 intentDescription = c.getString(intentIndex);                            
1923                                 long serialNumber = c.getInt(profileIdIndex);                            
1924                                 user = mUserManager.getUserForSerialNumber(serialNumber);                
1925                                 int promiseType = c.getInt(restoredIndex);                               
1926                                 int disabledState = 0;                                                   
1927                                 boolean itemReplaced = false;                                            
1928                                 if (user == null) {                                                      
1929                                     // User has been deleted remove the item.                            
1930                                     itemsToRemove.add(id);                                               
1931                                     continue;                                                            
1932                                 }                                                                        
1933                                 try {                                                                    
1934                                     intent = Intent.parseUri(intentDescription, 0);                      
1935                                     ComponentName cn = intent.getComponent();                            
1936                                     if (cn != null && cn.getPackageName() != null) {                     
1937                                         boolean validPkg = launcherApps.isPackageEnabledForProfile(      
1938                                                 cn.getPackageName(), user);                              
1939                                         boolean validComponent = validPkg &&                             
1940                                                 launcherApps.isActivityEnabledForProfile(cn, user);      
1941                                                                                                          
1942                                         if (validComponent) {                                            
1943                                             if (restored) {                                              
1944                                                 // no special handling necessary for this item           
1945                                                 restoredRows.add(id);                                    
1946                                                 restored = false;                                        
1947                                             }                                                            
1948                                         } else if (validPkg) {                                           
1949                                             intent = null;                                               
1950                                             if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
1951                                                 // We allow auto install apps to have their intent       
1952                                                 // updated after an install.                             
1953                                                 intent = manager.getLaunchIntentForPackage(              
1954                                                         cn.getPackageName());                            
1955                                                 if (intent != null) {                                    
1956                                                     ContentValues values = new ContentValues();          
1957                                                     values.put(LauncherSettings.Favorites.INTENT,        
1958                                                             intent.toUri(0));                            
1959                                                     updateItem(id, values);                              
1960                                                 }                                                        
1961                                             }                                                            
1962                                                                                                          
1963                                             if (intent == null) {                                        
1964                                                 // The app is installed but the component is no          
1965                                                 // longer available.                                     
1966                                                 Launcher.addDumpLog(TAG,                                 
1967                                                         "Invalid component removed: " + cn, true);       
1968                                                 itemsToRemove.add(id);                                   
1969                                                 continue;                                                
1970                                             } else {                                                     
1971                                                 // no special handling necessary for this item           
1972                                                 restoredRows.add(id);                                    
1973                                                 restored = false;                                        
1974                                             }                                                            
1975                                         } else if (restored) {                                           
1976                                             // Package is not yet available but might be                 
1977                                             // installed later.                                          
1978                                             Launcher.addDumpLog(TAG,                                     
1979                                                     "package not yet restored: " + cn, true);            
1980                                                                                                          
1981                                             if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
1982                                                 // Restore has started once.                             
1983                                             } else if (installingPkgs.contains(cn.getPackageName())) {   
1984                                                 // App restore has started. Update the flag              
1985                                                 promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;        
1986                                                 ContentValues values = new ContentValues();              
1987                                                 values.put(LauncherSettings.Favorites.RESTORED,          
1988                                                         promiseType);                                    
1989                                                 updateItem(id, values);                                  
1990                                             } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE🔵
1991                                                 // This is a common app. Try to replace this.            
1992                                                 int appType = CommonAppTypeParser.decodeItemTypeFromFlag(🔵
1993                                                 CommonAppTypeParser parser = new CommonAppTypeParser(id, 🔵
1994                                                 if (parser.findDefaultApp()) {                           
1995                                                     // Default app found. Replace it.                    
1996                                                     intent = parser.parsedIntent;                        
1997                                                     cn = intent.getComponent();                          
1998                                                     ContentValues values = parser.parsedValues;          
1999                                                     values.put(LauncherSettings.Favorites.RESTORED, 0);  
2000                                                     updateItem(id, values);                              
2001                                                     restored = false;                                    
2002                                                     itemReplaced = true;                                 
2003                                                                                                          
2004                                                 } else if (REMOVE_UNRESTORED_ICONS) {                    
2005                                                     Launcher.addDumpLog(TAG,                             
2006                                                             "Unrestored package removed: " + cn, true);  
2007                                                     itemsToRemove.add(id);                               
2008                                                     continue;                                            
2009                                                 }                                                        
2010                                             } else if (REMOVE_UNRESTORED_ICONS) {                        
2011                                                 Launcher.addDumpLog(TAG,                                 
2012                                                         "Unrestored package removed: " + cn, true);      
2013                                                 itemsToRemove.add(id);                                   
2014                                                 continue;                                                
2015                                             }                                                            
2016                                         } else if (launcherApps.isAppEnabled(                            
2017                                                 manager, cn.getPackageName(),                            
2018                                                 PackageManager.GET_UNINSTALLED_PACKAGES)) {              
2019                                             // Package is present but not available.                     
2020                                             allowMissingTarget = true;                                   
2021                                             disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;    
2022                                         } else if (!isSdCardReady) {                                     
2023                                             // SdCard is not ready yet. Package might get available,     
2024                                             // once it is ready.                                         
2025                                             Launcher.addDumpLog(TAG, "Invalid package: " + cn            
2026                                                     + " (check again later)", true);                     
2027                                             HashSet<String> pkgs = sPendingPackages.get(user);           
2028                                             if (pkgs == null) {                                          
2029                                                 pkgs = new HashSet<String>();                            
2030                                                 sPendingPackages.put(user, pkgs);                        
2031                                             }                                                            
2032                                             pkgs.add(cn.getPackageName());                               
2033                                             allowMissingTarget = true;                                   
2034                                             // Add the icon on the workspace anyway.                     
2035                                                                                                          
2036                                         } else {                                                         
2037                                             // Do not wait for external media load anymore.              
2038                                             // Log the invalid package, and remove it                    
2039                                             Launcher.addDumpLog(TAG,                                     
2040                                                     "Invalid package removed: " + cn, true);             
2041                                             itemsToRemove.add(id);                                       
2042                                             continue;                                                    
2043                                         }                                                                
2044                                     } else if (cn == null) {                                             
2045                                         // For shortcuts with no component, keep them as they are        
2046                                         restoredRows.add(id);                                            
2047                                         restored = false;                                                
2048                                     }                                                                    
2049                                 } catch (URISyntaxException e) {                                         
2050                                     Launcher.addDumpLog(TAG,                                             
2051                                             "Invalid uri: " + intentDescription, true);                  
2052                                     continue;                                                            
2053                                 }                                                                        
2054                                                                                                          
2055                                 if (itemReplaced) {                                                      
2056                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
2057                                         info = getAppShortcutInfo(manager, intent, user, context, null,  
2058                                                 iconIndex, titleIndex, false);                           
2059                                     } else {                                                             
2060                                         // Don't replace items for other profiles.                       
2061                                         itemsToRemove.add(id);                                           
2062                                         continue;                                                        
2063                                     }                                                                    
2064                                 } else if (restored) {                                                   
2065                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
2066                                         Launcher.addDumpLog(TAG,                                         
2067                                                 "constructing info for partially restored package",      
2068                                                 true);                                                   
2069                                         info = getRestoredItemInfo(c, titleIndex, intent, promiseType);  
2070                                         intent = getRestoredItemIntent(c, context, intent);              
2071                                     } else {                                                             
2072                                         // Don't restore items for other profiles.                       
2073                                         itemsToRemove.add(id);                                           
2074                                         continue;                                                        
2075                                     }                                                                    
2076                                 } else if (itemType ==                                                   
2077                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {              
2078                                     info = getAppShortcutInfo(manager, intent, user, context, c,         
2079                                             iconIndex, titleIndex, allowMissingTarget);                  
2080                                 } else {                                                                 
2081                                     info = getShortcutInfo(c, context, iconTypeIndex,                    
2082                                             iconPackageIndex, iconResourceIndex, iconIndex,              
2083                                             titleIndex);                                                 
2084                                                                                                          
2085                                     // App shortcuts that used to be automatically added to Launcher     
2086                                     // didn't always have the correct intent flags set, so do that       
2087                                     // here                                                              
2088                                     if (intent.getAction() != null &&                                    
2089                                         intent.getCategories() != null &&                                
2090                                         intent.getAction().equals(Intent.ACTION_MAIN) &&                 
2091                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {     
2092                                         intent.addFlags(                                                 
2093                                             Intent.FLAG_ACTIVITY_NEW_TASK |                              
2094                                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                  
2095                                     }                                                                    
2096                                 }                                                                        
2097                                                                                                          
2098                                 if (info != null) {                                                      
2099                                     info.id = id;                                                        
2100                                     info.intent = intent;                                                
2101                                     container = c.getInt(containerIndex);                                
2102                                     info.container = container;                                          
2103                                     info.screenId = c.getInt(screenIndex);                               
2104                                     info.cellX = c.getInt(cellXIndex);                                   
2105                                     info.cellY = c.getInt(cellYIndex);                                   
2106                                     info.rank = c.getInt(rankIndex);                                     
2107                                     info.spanX = 1;                                                      
2108                                     info.spanY = 1;                                                      
2109                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);          
2110                                     info.isDisabled = disabledState;                                     
2111                                     if (isSafeMode && !Utilities.isSystemApp(context, intent)) {         
2112                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;          
2113                                     }                                                                    
2114                                                                                                          
2115                                     // check & update map of what's occupied                             
2116                                     if (!checkItemPlacement(occupied, info)) {                           
2117                                         itemsToRemove.add(id);                                           
2118                                         break;                                                           
2119                                     }                                                                    
2120                                                                                                          
2121                                     switch (container) {                                                 
2122                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2123                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2124                                         sBgWorkspaceItems.add(info);                                     
2125                                         break;                                                           
2126                                     default:                                                             
2127                                         // Item is in a user folder                                      
2128                                         FolderInfo folderInfo =                                          
2129                                                 findOrMakeFolder(sBgFolders, container);                 
2130                                         folderInfo.add(info);                                            
2131                                         break;                                                           
2132                                     }                                                                    
2133                                     sBgItemsIdMap.put(info.id, info);                                    
2134                                 } else {                                                                 
2135                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2136                                 }                                                                        
2137                                 break;                                                                   
2138                                                                                                          
2139                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2140                                 id = c.getLong(idIndex);                                                 
2141                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2142                                                                                                          
2143                                 folderInfo.title = c.getString(titleIndex);                              
2144                                 folderInfo.id = id;                                                      
2145                                 container = c.getInt(containerIndex);                                    
2146                                 folderInfo.container = container;                                        
2147                                 folderInfo.screenId = c.getInt(screenIndex);                             
2148                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2149                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2150                                 folderInfo.spanX = 1;                                                    
2151                                 folderInfo.spanY = 1;                                                    
2152                                                                                                          
2153                                 // check & update map of what's occupied                                 
2154                                 if (!checkItemPlacement(occupied, folderInfo)) {                         
2155                                     itemsToRemove.add(id);                                               
2156                                     break;                                                               
2157                                 }                                                                        
2158                                                                                                          
2159                                 switch (container) {                                                     
2160                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2161                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2162                                         sBgWorkspaceItems.add(folderInfo);                               
2163                                         break;                                                           
2164                                 }                                                                        
2165                                                                                                          
2166                                 if (restored) {                                                          
2167                                     // no special handling required for restored folders                 
2168                                     restoredRows.add(id);                                                
2169                                 }                                                                        
2170                                                                                                          
2171                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2172                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2173                                 break;                                                                   
2174                                                                                                          
2175                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2176                             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                  
2177                                 // Read all Launcher-specific widget details                             
2178                                 boolean customWidget = itemType ==                                       
2179                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;               
2180                                                                                                          
2181                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2182                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2183                                 id = c.getLong(idIndex);                                                 
2184                                 final ComponentName component =                                          
2185                                         ComponentName.unflattenFromString(savedProvider);                
2186                                                                                                          
2187                                 final int restoreStatus = c.getInt(restoredIndex);                       
2188                                 final boolean isIdValid = (restoreStatus &                               
2189                                         LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                   
2190                                                                                                          
2191                                 final boolean wasProviderReady = (restoreStatus &                        
2192                                         LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;             
2193                                                                                                          
2194                                 final LauncherAppWidgetProviderInfo provider =                           
2195                                         LauncherModel.getProviderInfo(context,                           
2196                                                 ComponentName.unflattenFromString(savedProvider));       
2197                                                                                                          
2198                                 final boolean isProviderReady = isValidProvider(provider);               
2199                                 if (!isSafeMode && !customWidget &&                                      
2200                                         wasProviderReady && !isProviderReady) {                          
2201                                     String log = "Deleting widget that isn't installed anymore: "        
2202                                             + "id=" + id + " appWidgetId=" + appWidgetId;                
2203                                                                                                          
2204                                     Log.e(TAG, log);                                                     
2205                                     Launcher.addDumpLog(TAG, log, false);                                
2206                                     itemsToRemove.add(id);                                               
2207                                 } else {                                                                 
2208                                     if (isProviderReady) {                                               
2209                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2210                                                 provider.provider);                                      
2211                                                                                                          
2212                                         if (!customWidget) {                                             
2213                                             int[] minSpan =                                              
2214                                                     Launcher.getMinSpanForWidget(context, provider);     
2215                                             appWidgetInfo.minSpanX = minSpan[0];                         
2216                                             appWidgetInfo.minSpanY = minSpan[1];                         
2217                                         }                                                                
2218                                                                                                          
2219                                         int status = restoreStatus;                                      
2220                                         if (!wasProviderReady) {                                         
2221                                             // If provider was not previously ready, update the          
2222                                             // status and UI flag.                                       
2223                                                                                                          
2224                                             // Id would be valid only if the widget restore broadcast was🔵
2225                                             if (isIdValid) {                                             
2226                                                 status = LauncherAppWidgetInfo.RESTORE_COMPLETED;        
2227                                             } else {                                                     
2228                                                 status &= ~LauncherAppWidgetInfo                         
2229                                                         .FLAG_PROVIDER_NOT_READY;                        
2230                                             }                                                            
2231                                         }                                                                
2232                                         appWidgetInfo.restoreStatus = status;                            
2233                                     } else {                                                             
2234                                         Log.v(TAG, "Widget restore pending id=" + id                     
2235                                                 + " appWidgetId=" + appWidgetId                          
2236                                                 + " status =" + restoreStatus);                          
2237                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2238                                                 component);                                              
2239                                         appWidgetInfo.restoreStatus = restoreStatus;                     
2240                                                                                                          
2241                                         if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) 🔵
2242                                             // Restore has started once.                                 
2243                                         } else if (installingPkgs.contains(component.getPackageName())) {
2244                                             // App restore has started. Update the flag                  
2245                                             appWidgetInfo.restoreStatus |=                               
2246                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;          
2247                                         } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {             
2248                                             Launcher.addDumpLog(TAG,                                     
2249                                                     "Unrestored widget removed: " + component, true);    
2250                                             itemsToRemove.add(id);                                       
2251                                             continue;                                                    
2252                                         }                                                                
2253                                     }                                                                    
2254                                                                                                          
2255                                     appWidgetInfo.id = id;                                               
2256                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2257                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2258                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2259                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2260                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2261                                                                                                          
2262                                     if (!customWidget) {                                                 
2263                                         int[] minSpan = Launcher.getMinSpanForWidget(context, provider); 
2264                                         appWidgetInfo.minSpanX = minSpan[0];                             
2265                                         appWidgetInfo.minSpanY = minSpan[1];                             
2266                                     }                                                                    
2267                                                                                                          
2268                                     container = c.getInt(containerIndex);                                
2269                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2270                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2271                                         Log.e(TAG, "Widget found where container != " +                  
2272                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2273                                         continue;                                                        
2274                                     }                                                                    
2275                                                                                                          
2276                                     appWidgetInfo.container = c.getInt(containerIndex);                  
2277                                     // check & update map of what's occupied                             
2278                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {                  
2279                                         itemsToRemove.add(id);                                           
2280                                         break;                                                           
2281                                     }                                                                    
2282                                                                                                          
2283                                     if (!customWidget) {                                                 
2284                                         String providerName =                                            
2285                                                 appWidgetInfo.providerName.flattenToString();            
2286                                         if (!providerName.equals(savedProvider) ||                       
2287                                                 (appWidgetInfo.restoreStatus != restoreStatus)) {        
2288                                             ContentValues values = new ContentValues();                  
2289                                             values.put(                                                  
2290                                                     LauncherSettings.Favorites.APPWIDGET_PROVIDER,       
2291                                                     providerName);                                       
2292                                             values.put(LauncherSettings.Favorites.RESTORED,              
2293                                                     appWidgetInfo.restoreStatus);                        
2294                                             updateItem(id, values);                                      
2295                                         }                                                                
2296                                     }                                                                    
2297                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2298                                     sBgAppWidgets.add(appWidgetInfo);                                    
2299                                 }                                                                        
2300                                 break;                                                                   
2301                             }                                                                            
2302                         } catch (Exception e) {                                                          
2303                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2304                         }                                                                                
2305                     }                                                                                    
2306                 } finally {                                                                              
2307                     if (c != null) {                                                                     
2308                         c.close();                                                                       
2309                     }                                                                                    
2310                 }                                                                                        
2311                                                                                                          
2312                 // Break early if we've stopped loading                                                  
2313                 if (mStopped) {                                                                          
2314                     clearSBgDataStructures();                                                            
2315                     return;                                                                              
2316                 }                                                                                        
2317                                                                                                          
2318                 if (itemsToRemove.size() > 0) {                                                          
2319                     ContentProviderClient client = contentResolver.acquireContentProviderClient(         
2320                             contentUri);                                                                 
2321                     // Remove dead items                                                                 
2322                     for (long id : itemsToRemove) {                                                      
2323                         if (DEBUG_LOADERS) {                                                             
2324                             Log.d(TAG, "Removed id = " + id);                                            
2325                         }                                                                                
2326                         // Don't notify content observers                                                
2327                         try {                                                                            
2328                             client.delete(LauncherSettings.Favorites.getContentUri(id, false),           
2329                                     null, null);                                                         
2330                         } catch (RemoteException e) {                                                    
2331                             Log.w(TAG, "Could not remove id = " + id);                                   
2332                         }                                                                                
2333                     }                                                                                    
2334                 }                                                                                        
2335                                                                                                          
2336                 if (restoredRows.size() > 0) {                                                           
2337                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(        
2338                             contentUri);                                                                 
2339                     // Update restored items that no longer require special handling                     
2340                     try {                                                                                
2341                         StringBuilder selectionBuilder = new StringBuilder();                            
2342                         selectionBuilder.append(LauncherSettings.Favorites._ID);                         
2343                         selectionBuilder.append(" IN (");                                                
2344                         selectionBuilder.append(TextUtils.join(", ", restoredRows));                     
2345                         selectionBuilder.append(")");                                                    
2346                         ContentValues values = new ContentValues();                                      
2347                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2348                         updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,           
2349                                 values, selectionBuilder.toString(), null);                              
2350                     } catch (RemoteException e) {                                                        
2351                         Log.w(TAG, "Could not update restored rows");                                    
2352                     }                                                                                    
2353                 }                                                                                        
2354                                                                                                          
2355                 if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                     
2356                     context.registerReceiver(new AppsAvailabilityCheck(),                                
2357                             new IntentFilter(StartupReceiver.SYSTEM_READY),                              
2358                             null, sWorker);                                                              
2359                 }                                                                                        
2360                                                                                                          
2361                 sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                            
2362                 // Log to disk                                                                           
2363                 Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                          
2364                         TextUtils.join(", ", sBgWorkspaceScreens), true);                                
2365                                                                                                          
2366                 // Remove any empty screens                                                              
2367                 ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                
2368                 for (ItemInfo item: sBgItemsIdMap.values()) {                                            
2369                     long screenId = item.screenId;                                                       
2370                     if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                
2371                             unusedScreens.contains(screenId)) {                                          
2372                         unusedScreens.remove(screenId);                                                  
2373                     }                                                                                    
2374                 }                                                                                        
2375                                                                                                          
2376                 // If there are any empty screens remove them, and update.                               
2377                 if (unusedScreens.size() != 0) {                                                         
2378                     // Log to disk                                                                       
2379                     Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +            
2380                             TextUtils.join(", ", unusedScreens), true);                                  
2381                                                                                                          
2382                     sBgWorkspaceScreens.removeAll(unusedScreens);                                        
2383                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2384                 }                                                                                        
2385                                                                                                          
2386                 if (DEBUG_LOADERS) {                                                                     
2387                     Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");          
2388                     Log.d(TAG, "workspace layout: ");                                                    
2389                     int nScreens = occupied.size();                                                      
2390                     for (int y = 0; y < countY; y++) {                                                   
2391                         String line = "";                                                                
2392                                                                                                          
2393                         Iterator<Long> iter = occupied.keySet().iterator();                              
2394                         while (iter.hasNext()) {                                                         
2395                             long screenId = iter.next();                                                 
2396                             if (screenId > 0) {                                                          
2397                                 line += " | ";                                                           
2398                             }                                                                            
2399                             for (int x = 0; x < countX; x++) {                                           
2400                                 ItemInfo[][] screen = occupied.get(screenId);                            
2401                                 if (x < screen.length && y < screen[x].length) {                         
2402                                     line += (screen[x][y] != null) ? "#" : ".";                          
2403                                 } else {                                                                 
2404                                     line += "!";                                                         
2405                                 }                                                                        
2406                             }                                                                            
2407                         }                                                                                
2408                         Log.d(TAG, "[ " + line + " ]");                                                  
2409                     }                                                                                    
2410                 }                                                                                        
2411             }                                                                                            
2412         }                                                                                                
2413                                                                                                          
2414         /**                                                                                              
2415          * Partially updates the item without any notification. Must be called on the worker thread.     
2416          */                                                                                              
2417         private void updateItem(long itemId, ContentValues update) {                                     
2418             mContext.getContentResolver().update(                                                        
2419                     LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                              
2420                     update,                                                                              
2421                     BaseColumns._ID + "= ?",                                                             
2422                     new String[]{Long.toString(itemId)});                                                
2423         }                                                                                                
2424                                                                                                          
2425         /** Filters the set of items who are directly or indirectly (via another container) on the       
2426          * specified screen. */                                                                          
2427         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2428                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2429                 ArrayList<ItemInfo> currentScreenItems,                                                  
2430                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2431             // Purge any null ItemInfos                                                                  
2432             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2433             while (iter.hasNext()) {                                                                     
2434                 ItemInfo i = iter.next();                                                                
2435                 if (i == null) {                                                                         
2436                     iter.remove();                                                                       
2437                 }                                                                                        
2438             }                                                                                            
2439                                                                                                          
2440             // Order the set of items by their containers first, this allows use to walk through the     
2441             // list sequentially, build up a list of containers that are in the specified screen,        
2442             // as well as all items in those containers.                                                 
2443             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2444             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2445                 @Override                                                                                
2446                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2447                     return (int) (lhs.container - rhs.container);                                        
2448                 }                                                                                        
2449             });                                                                                          
2450             for (ItemInfo info : allWorkspaceItems) {                                                    
2451                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2452                     if (info.screenId == currentScreenId) {                                              
2453                         currentScreenItems.add(info);                                                    
2454                         itemsOnScreen.add(info.id);                                                      
2455                     } else {                                                                             
2456                         otherScreenItems.add(info);                                                      
2457                     }                                                                                    
2458                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2459                     currentScreenItems.add(info);                                                        
2460                     itemsOnScreen.add(info.id);                                                          
2461                 } else {                                                                                 
2462                     if (itemsOnScreen.contains(info.container)) {                                        
2463                         currentScreenItems.add(info);                                                    
2464                         itemsOnScreen.add(info.id);                                                      
2465                     } else {                                                                             
2466                         otherScreenItems.add(info);                                                      
2467                     }                                                                                    
2468                 }                                                                                        
2469             }                                                                                            
2470         }                                                                                                
2471                                                                                                          
2472         /** Filters the set of widgets which are on the specified screen. */                             
2473         private void filterCurrentAppWidgets(long currentScreenId,                                       
2474                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2475                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2476                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2477                                                                                                          
2478             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2479                 if (widget == null) continue;                                                            
2480                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2481                         widget.screenId == currentScreenId) {                                            
2482                     currentScreenWidgets.add(widget);                                                    
2483                 } else {                                                                                 
2484                     otherScreenWidgets.add(widget);                                                      
2485                 }                                                                                        
2486             }                                                                                            
2487         }                                                                                                
2488                                                                                                          
2489         /** Filters the set of folders which are on the specified screen. */                             
2490         private void filterCurrentFolders(long currentScreenId,                                          
2491                 HashMap<Long, ItemInfo> itemsIdMap,                                                      
2492                 HashMap<Long, FolderInfo> folders,                                                       
2493                 HashMap<Long, FolderInfo> currentScreenFolders,                                          
2494                 HashMap<Long, FolderInfo> otherScreenFolders) {                                          
2495                                                                                                          
2496             for (long id : folders.keySet()) {                                                           
2497                 ItemInfo info = itemsIdMap.get(id);                                                      
2498                 FolderInfo folder = folders.get(id);                                                     
2499                 if (info == null || folder == null) continue;                                            
2500                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2501                         info.screenId == currentScreenId) {                                              
2502                     currentScreenFolders.put(id, folder);                                                
2503                 } else {                                                                                 
2504                     otherScreenFolders.put(id, folder);                                                  
2505                 }                                                                                        
2506             }                                                                                            
2507         }                                                                                                
2508                                                                                                          
2509         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2510          * right) */                                                                                     
2511         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2512             final LauncherAppState app = LauncherAppState.getInstance();                                 
2513             final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                          
2514             // XXX: review this                                                                          
2515             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2516                 @Override                                                                                
2517                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2518                     int cellCountX = (int) grid.numColumns;                                              
2519                     int cellCountY = (int) grid.numRows;                                                 
2520                     int screenOffset = cellCountX * cellCountY;                                          
2521                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2522                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2523                             lhs.cellY * cellCountX + lhs.cellX);                                         
2524                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2525                             rhs.cellY * cellCountX + rhs.cellX);                                         
2526                     return (int) (lr - rr);                                                              
2527                 }                                                                                        
2528             });                                                                                          
2529         }                                                                                                
2530                                                                                                          
2531         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2532                 final ArrayList<Long> orderedScreens) {                                                  
2533             final Runnable r = new Runnable() {                                                          
2534                 @Override                                                                                
2535                 public void run() {                                                                      
2536                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2537                     if (callbacks != null) {                                                             
2538                         callbacks.bindScreens(orderedScreens);                                           
2539                     }                                                                                    
2540                 }                                                                                        
2541             };                                                                                           
2542             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2543         }                                                                                                
2544                                                                                                          
2545         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2546                 final ArrayList<ItemInfo> workspaceItems,                                                
2547                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2548                 final HashMap<Long, FolderInfo> folders,                                                 
2549                 ArrayList<Runnable> deferredBindRunnables) {                                             
2550                                                                                                          
2551             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2552                                                                                                          
2553             // Bind the workspace items                                                                  
2554             int N = workspaceItems.size();                                                               
2555             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2556                 final int start = i;                                                                     
2557                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2558                 final Runnable r = new Runnable() {                                                      
2559                     @Override                                                                            
2560                     public void run() {                                                                  
2561                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2562                         if (callbacks != null) {                                                         
2563                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2564                                     false);                                                              
2565                         }                                                                                
2566                     }                                                                                    
2567                 };                                                                                       
2568                 if (postOnMainThread) {                                                                  
2569                     synchronized (deferredBindRunnables) {                                               
2570                         deferredBindRunnables.add(r);                                                    
2571                     }                                                                                    
2572                 } else {                                                                                 
2573                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2574                 }                                                                                        
2575             }                                                                                            
2576                                                                                                          
2577             // Bind the folders                                                                          
2578             if (!folders.isEmpty()) {                                                                    
2579                 final Runnable r = new Runnable() {                                                      
2580                     public void run() {                                                                  
2581                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2582                         if (callbacks != null) {                                                         
2583                             callbacks.bindFolders(folders);                                              
2584                         }                                                                                
2585                     }                                                                                    
2586                 };                                                                                       
2587                 if (postOnMainThread) {                                                                  
2588                     synchronized (deferredBindRunnables) {                                               
2589                         deferredBindRunnables.add(r);                                                    
2590                     }                                                                                    
2591                 } else {                                                                                 
2592                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2593                 }                                                                                        
2594             }                                                                                            
2595                                                                                                          
2596             // Bind the widgets, one at a time                                                           
2597             N = appWidgets.size();                                                                       
2598             for (int i = 0; i < N; i++) {                                                                
2599                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2600                 final Runnable r = new Runnable() {                                                      
2601                     public void run() {                                                                  
2602                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2603                         if (callbacks != null) {                                                         
2604                             callbacks.bindAppWidget(widget);                                             
2605                         }                                                                                
2606                     }                                                                                    
2607                 };                                                                                       
2608                 if (postOnMainThread) {                                                                  
2609                     deferredBindRunnables.add(r);                                                        
2610                 } else {                                                                                 
2611                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2612                 }                                                                                        
2613             }                                                                                            
2614         }                                                                                                
2615                                                                                                          
2616         /**                                                                                              
2617          * Binds all loaded data to actual views on the main thread.                                     
2618          */                                                                                              
2619         private void bindWorkspace(int synchronizeBindPage) {                                            
2620             final long t = SystemClock.uptimeMillis();                                                   
2621             Runnable r;                                                                                  
2622                                                                                                          
2623             // Don't use these two variables in any of the callback runnables.                           
2624             // Otherwise we hold a reference to them.                                                    
2625             final Callbacks oldCallbacks = mCallbacks.get();                                             
2626             if (oldCallbacks == null) {                                                                  
2627                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2628                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2629                 return;                                                                                  
2630             }                                                                                            
2631                                                                                                          
2632             // Save a copy of all the bg-thread collections                                              
2633             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2634             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2635                     new ArrayList<LauncherAppWidgetInfo>();                                              
2636             HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                         
2637             HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                          
2638             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2639             synchronized (sBgLock) {                                                                     
2640                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2641                 appWidgets.addAll(sBgAppWidgets);                                                        
2642                 folders.putAll(sBgFolders);                                                              
2643                 itemsIdMap.putAll(sBgItemsIdMap);                                                        
2644                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2645             }                                                                                            
2646                                                                                                          
2647             final boolean isLoadingSynchronously =                                                       
2648                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2649             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2650                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2651             if (currScreen >= orderedScreenIds.size()) {                                                 
2652                 // There may be no workspace screens (just hotseat items and an empty page).             
2653                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2654             }                                                                                            
2655             final int currentScreen = currScreen;                                                        
2656             final long currentScreenId = currentScreen < 0                                               
2657                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2658                                                                                                          
2659             // Load all the items that are on the current page first (and in the process, unbind         
2660             // all the existing workspace items before we call startBinding() below.                     
2661             unbindWorkspaceItemsOnMainThread();                                                          
2662                                                                                                          
2663             // Separate the items that are on the current screen, and all the other remaining items      
2664             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2665             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2666             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2667                     new ArrayList<LauncherAppWidgetInfo>();                                              
2668             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2669                     new ArrayList<LauncherAppWidgetInfo>();                                              
2670             HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                  
2671             HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                    
2672                                                                                                          
2673             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2674                     otherWorkspaceItems);                                                                
2675             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2676                     otherAppWidgets);                                                                    
2677             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2678                     otherFolders);                                                                       
2679             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2680             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2681                                                                                                          
2682             // Tell the workspace that we're about to start binding items                                
2683             r = new Runnable() {                                                                         
2684                 public void run() {                                                                      
2685                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2686                     if (callbacks != null) {                                                             
2687                         callbacks.startBinding();                                                        
2688                     }                                                                                    
2689                 }                                                                                        
2690             };                                                                                           
2691             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2692                                                                                                          
2693             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2694                                                                                                          
2695             // Load items on the current page                                                            
2696             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2697                     currentFolders, null);                                                               
2698             if (isLoadingSynchronously) {                                                                
2699                 r = new Runnable() {                                                                     
2700                     public void run() {                                                                  
2701                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2702                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2703                             callbacks.onPageBoundSynchronously(currentScreen);                           
2704                         }                                                                                
2705                     }                                                                                    
2706                 };                                                                                       
2707                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2708             }                                                                                            
2709                                                                                                          
2710             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2711             // work until after the first render)                                                        
2712             synchronized (mDeferredBindRunnables) {                                                      
2713                 mDeferredBindRunnables.clear();                                                          
2714             }                                                                                            
2715             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2716                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2717                                                                                                          
2718             // Tell the workspace that we're done binding items                                          
2719             r = new Runnable() {                                                                         
2720                 public void run() {                                                                      
2721                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2722                     if (callbacks != null) {                                                             
2723                         callbacks.finishBindingItems();                                                  
2724                     }                                                                                    
2725                                                                                                          
2726                     // If we're profiling, ensure this is the last thing in the queue.                   
2727                     if (DEBUG_LOADERS) {                                                                 
2728                         Log.d(TAG, "bound workspace in "                                                 
2729                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2730                     }                                                                                    
2731                                                                                                          
2732                     mIsLoadingAndBindingWorkspace = false;                                               
2733                 }                                                                                        
2734             };                                                                                           
2735             if (isLoadingSynchronously) {                                                                
2736                 synchronized (mDeferredBindRunnables) {                                                  
2737                     mDeferredBindRunnables.add(r);                                                       
2738                 }                                                                                        
2739             } else {                                                                                     
2740                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2741             }                                                                                            
2742         }                                                                                                
2743                                                                                                          
2744         private void loadAndBindAllApps() {                                                              
2745             if (DEBUG_LOADERS) {                                                                         
2746                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2747             }                                                                                            
2748             if (!mAllAppsLoaded) {                                                                       
2749                 loadAllApps();                                                                           
2750                 synchronized (LoaderTask.this) {                                                         
2751                     if (mStopped) {                                                                      
2752                         return;                                                                          
2753                     }                                                                                    
2754                     mAllAppsLoaded = true;                                                               
2755                 }                                                                                        
2756             } else {                                                                                     
2757                 onlyBindAllApps();                                                                       
2758             }                                                                                            
2759         }                                                                                                
2760                                                                                                          
2761         private void onlyBindAllApps() {                                                                 
2762             final Callbacks oldCallbacks = mCallbacks.get();                                             
2763             if (oldCallbacks == null) {                                                                  
2764                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2765                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2766                 return;                                                                                  
2767             }                                                                                            
2768                                                                                                          
2769             // shallow copy                                                                              
2770             @SuppressWarnings("unchecked")                                                               
2771             final ArrayList<AppInfo> list                                                                
2772                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2773             Runnable r = new Runnable() {                                                                
2774                 public void run() {                                                                      
2775                     final long t = SystemClock.uptimeMillis();                                           
2776                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2777                     if (callbacks != null) {                                                             
2778                         callbacks.bindAllApplications(list);                                             
2779                     }                                                                                    
2780                     if (DEBUG_LOADERS) {                                                                 
2781                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2782                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2783                     }                                                                                    
2784                 }                                                                                        
2785             };                                                                                           
2786             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2787             if (isRunningOnMainThread) {                                                                 
2788                 r.run();                                                                                 
2789             } else {                                                                                     
2790                 mHandler.post(r);                                                                        
2791             }                                                                                            
2792         }                                                                                                
2793                                                                                                          
2794         private void loadAllApps() {                                                                     
2795             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2796                                                                                                          
2797             final Callbacks oldCallbacks = mCallbacks.get();                                             
2798             if (oldCallbacks == null) {                                                                  
2799                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2800                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2801                 return;                                                                                  
2802             }                                                                                            
2803                                                                                                          
2804             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                              
2805             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                            
2806                                                                                                          
2807             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                      
2808                                                                                                          
2809             // Clear the list of apps                                                                    
2810             mBgAllAppsList.clear();                                                                      
2811             SharedPreferences prefs = mContext.getSharedPreferences(                                     
2812                     LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                   
2813             for (UserHandleCompat user : profiles) {                                                     
2814                 // Query for the set of apps                                                             
2815                 final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                     
2816                 List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);       
2817                 if (DEBUG_LOADERS) {                                                                     
2818                     Log.d(TAG, "getActivityList took "                                                   
2819                             + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);             
2820                     Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);         
2821                 }                                                                                        
2822                 // Fail if we don't have any apps                                                        
2823                 // TODO: Fix this. Only fail for the current user.                                       
2824                 if (apps == null || apps.isEmpty()) {                                                    
2825                     return;                                                                              
2826                 }                                                                                        
2827                                                                                                          
2828                 // Update icon cache                                                                     
2829                 HashSet<String> updatedPackages = mIconCache.updateDBIcons(user, apps);                  
2830                                                                                                          
2831                 // If any package icon has changed (app was updated while launcher was dead),            
2832                 // update the corresponding shortcuts.                                                   
2833                 if (!updatedPackages.isEmpty()) {                                                        
2834                     final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();               
2835                     synchronized (sBgLock) {                                                             
2836                         for (ItemInfo info : sBgItemsIdMap.values()) {                                   
2837                             if (info instanceof ShortcutInfo && user.equals(info.user)                   
2838                                     && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION)🔵
2839                                 ShortcutInfo si = (ShortcutInfo) info;                                   
2840                                 ComponentName cn = si.getTargetComponent();                              
2841                                 if (cn != null && updatedPackages.contains(cn.getPackageName())) {       
2842                                     si.updateIcon(mIconCache);                                           
2843                                     updates.add(si);                                                     
2844                                 }                                                                        
2845                             }                                                                            
2846                         }                                                                                
2847                     }                                                                                    
2848                                                                                                          
2849                     if (!updates.isEmpty()) {                                                            
2850                         final UserHandleCompat userFinal = user;                                         
2851                         mHandler.post(new Runnable() {                                                   
2852                                                                                                          
2853                             public void run() {                                                          
2854                                 Callbacks cb = getCallback();                                            
2855                                 if (cb != null) {                                                        
2856                                     cb.bindShortcutsChanged(                                             
2857                                             updates, new ArrayList<ShortcutInfo>(), userFinal);          
2858                                 }                                                                        
2859                             }                                                                            
2860                         });                                                                              
2861                     }                                                                                    
2862                 }                                                                                        
2863                                                                                                          
2864                 // Create the ApplicationInfos                                                           
2865                 for (int i = 0; i < apps.size(); i++) {                                                  
2866                     LauncherActivityInfoCompat app = apps.get(i);                                        
2867                     // This builds the icon bitmaps.                                                     
2868                     mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                    
2869                 }                                                                                        
2870                                                                                                          
2871                 if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {    
2872                     // Add shortcuts for packages which were installed while launcher was dead.          
2873                     String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                              
2874                             + mUserManager.getSerialNumberForUser(user);                                 
2875                     Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET🔵
2876                     HashSet<String> newPackageSet = new HashSet<String>();                               
2877                                                                                                          
2878                     for (LauncherActivityInfoCompat info : apps) {                                       
2879                         String packageName = info.getComponentName().getPackageName();                   
2880                         if (!packagesAdded.contains(packageName)                                         
2881                                 && !newPackageSet.contains(packageName)) {                               
2882                             InstallShortcutReceiver.queueInstallShortcut(info, mContext);                
2883                         }                                                                                
2884                         newPackageSet.add(packageName);                                                  
2885                     }                                                                                    
2886                                                                                                          
2887                     prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                  
2888                 }                                                                                        
2889             }                                                                                            
2890             // Huh? Shouldn't this be inside the Runnable below?                                         
2891             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2892             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2893                                                                                                          
2894             // Post callback on main thread                                                              
2895             mHandler.post(new Runnable() {                                                               
2896                 public void run() {                                                                      
2897                     final long bindTime = SystemClock.uptimeMillis();                                    
2898                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2899                     if (callbacks != null) {                                                             
2900                         callbacks.bindAllApplications(added);                                            
2901                         if (DEBUG_LOADERS) {                                                             
2902                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2903                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2904                         }                                                                                
2905                     } else {                                                                             
2906                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2907                     }                                                                                    
2908                 }                                                                                        
2909             });                                                                                          
2910                                                                                                          
2911             if (DEBUG_LOADERS) {                                                                         
2912                 Log.d(TAG, "Icons processed in "                                                         
2913                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2914             }                                                                                            
2915         }                                                                                                
2916                                                                                                          
2917         public void dumpState() {                                                                        
2918             synchronized (sBgLock) {                                                                     
2919                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2920                 Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                  
2921                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2922                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2923                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2924             }                                                                                            
2925         }                                                                                                
2926     }                                                                                                    
2927                                                                                                          
2928     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2929         sWorker.post(task);                                                                              
2930     }                                                                                                    
2931                                                                                                          
2932     private class AppsAvailabilityCheck extends BroadcastReceiver {                                      
2933                                                                                                          
2934         @Override                                                                                        
2935         public void onReceive(Context context, Intent intent) {                                          
2936             synchronized (sBgLock) {                                                                     
2937                 final LauncherAppsCompat launcherApps = LauncherAppsCompat                               
2938                         .getInstance(mApp.getContext());                                                 
2939                 final PackageManager manager = context.getPackageManager();                              
2940                 final ArrayList<String> packagesRemoved = new ArrayList<String>();                       
2941                 final ArrayList<String> packagesUnavailable = new ArrayList<String>();                   
2942                 for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {     
2943                     UserHandleCompat user = entry.getKey();                                              
2944                     packagesRemoved.clear();                                                             
2945                     packagesUnavailable.clear();                                                         
2946                     for (String pkg : entry.getValue()) {                                                
2947                         if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                       
2948                             boolean packageOnSdcard = launcherApps.isAppEnabled(                         
2949                                     manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);              
2950                             if (packageOnSdcard) {                                                       
2951                                 Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);      
2952                                 packagesUnavailable.add(pkg);                                            
2953                             } else {                                                                     
2954                                 Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);             
2955                                 packagesRemoved.add(pkg);                                                
2956                             }                                                                            
2957                         }                                                                                
2958                     }                                                                                    
2959                     if (!packagesRemoved.isEmpty()) {                                                    
2960                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,       
2961                                 packagesRemoved.toArray(new String[packagesRemoved.size()]), user));     
2962                     }                                                                                    
2963                     if (!packagesUnavailable.isEmpty()) {                                                
2964                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,  
2965                                 packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user🔵
2966                     }                                                                                    
2967                 }                                                                                        
2968                 sPendingPackages.clear();                                                                
2969             }                                                                                            
2970         }                                                                                                
2971     }                                                                                                    
2972                                                                                                          
2973     private class PackageUpdatedTask implements Runnable {                                               
2974         int mOp;                                                                                         
2975         String[] mPackages;                                                                              
2976         UserHandleCompat mUser;                                                                          
2977                                                                                                          
2978         public static final int OP_NONE = 0;                                                             
2979         public static final int OP_ADD = 1;                                                              
2980         public static final int OP_UPDATE = 2;                                                           
2981         public static final int OP_REMOVE = 3; // uninstlled                                             
2982         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2983                                                                                                          
2984                                                                                                          
2985         public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                    
2986             mOp = op;                                                                                    
2987             mPackages = packages;                                                                        
2988             mUser = user;                                                                                
2989         }                                                                                                
2990                                                                                                          
2991         public void run() {                                                                              
2992             final Context context = mApp.getContext();                                                   
2993                                                                                                          
2994             final String[] packages = mPackages;                                                         
2995             final int N = packages.length;                                                               
2996             switch (mOp) {                                                                               
2997                 case OP_ADD:                                                                             
2998                     for (int i=0; i<N; i++) {                                                            
2999                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);         
3000                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
3001                         mBgAllAppsList.addPackage(context, packages[i], mUser);                          
3002                     }                                                                                    
3003                                                                                                          
3004                     // Auto add shortcuts for added packages.                                            
3005                     if (ADD_MANAGED_PROFILE_SHORTCUTS                                                    
3006                             && !UserHandleCompat.myUserHandle().equals(mUser)) {                         
3007                         SharedPreferences prefs = context.getSharedPreferences(                          
3008                                 LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);       
3009                         String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                          
3010                                 + mUserManager.getSerialNumberForUser(mUser);                            
3011                         Set<String> shortcutSet = new HashSet<String>(                                   
3012                                 prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));              
3013                                                                                                          
3014                         for (int i=0; i<N; i++) {                                                        
3015                             if (!shortcutSet.contains(packages[i])) {                                    
3016                                 shortcutSet.add(packages[i]);                                            
3017                                 List<LauncherActivityInfoCompat> activities =                            
3018                                         mLauncherApps.getActivityList(packages[i], mUser);               
3019                                 if (activities != null && !activities.isEmpty()) {                       
3020                                     InstallShortcutReceiver.queueInstallShortcut(                        
3021                                             activities.get(0), context);                                 
3022                                 }                                                                        
3023                             }                                                                            
3024                         }                                                                                
3025                                                                                                          
3026                         prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                
3027                     }                                                                                    
3028                     break;                                                                               
3029                 case OP_UPDATE:                                                                          
3030                     for (int i=0; i<N; i++) {                                                            
3031                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);      
3032                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
3033                         mBgAllAppsList.updatePackage(context, packages[i], mUser);                       
3034                         WidgetPreviewLoader.removePackageFromDb(                                         
3035                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
3036                     }                                                                                    
3037                     break;                                                                               
3038                 case OP_REMOVE:                                                                          
3039                     // Remove the packageName for the set of auto-installed shortcuts. This              
3040                     // will ensure that the shortcut when the app is installed again.                    
3041                     if (ADD_MANAGED_PROFILE_SHORTCUTS                                                    
3042                             && !UserHandleCompat.myUserHandle().equals(mUser)) {                         
3043                         SharedPreferences prefs = context.getSharedPreferences(                          
3044                                 LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);       
3045                         String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                          
3046                                 + mUserManager.getSerialNumberForUser(mUser);                            
3047                         HashSet<String> shortcutSet = new HashSet<String>(                               
3048                                 prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));             
3049                         shortcutSet.removeAll(Arrays.asList(mPackages));                                 
3050                         prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                
3051                     }                                                                                    
3052                     for (int i=0; i<N; i++) {                                                            
3053                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3054                         mIconCache.removeIconsForPkg(packages[i], mUser);                                
3055                     }                                                                                    
3056                     // Fall through                                                                      
3057                 case OP_UNAVAILABLE:                                                                     
3058                     for (int i=0; i<N; i++) {                                                            
3059                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3060                         mBgAllAppsList.removePackage(packages[i], mUser);                                
3061                         WidgetPreviewLoader.removePackageFromDb(                                         
3062                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
3063                     }                                                                                    
3064                     break;                                                                               
3065             }                                                                                            
3066                                                                                                          
3067             ArrayList<AppInfo> added = null;                                                             
3068             ArrayList<AppInfo> modified = null;                                                          
3069             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
3070                                                                                                          
3071             if (mBgAllAppsList.added.size() > 0) {                                                       
3072                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
3073                 mBgAllAppsList.added.clear();                                                            
3074             }                                                                                            
3075             if (mBgAllAppsList.modified.size() > 0) {                                                    
3076                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
3077                 mBgAllAppsList.modified.clear();                                                         
3078             }                                                                                            
3079             if (mBgAllAppsList.removed.size() > 0) {                                                     
3080                 removedApps.addAll(mBgAllAppsList.removed);                                              
3081                 mBgAllAppsList.removed.clear();                                                          
3082             }                                                                                            
3083                                                                                                          
3084             final Callbacks callbacks = getCallback();                                                   
3085             if (callbacks == null) {                                                                     
3086                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
3087                 return;                                                                                  
3088             }                                                                                            
3089                                                                                                          
3090             final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                   
3091                     new HashMap<ComponentName, AppInfo>();                                               
3092                                                                                                          
3093             if (added != null) {                                                                         
3094                 addAppsToAllApps(context, added);                                                        
3095                 for (AppInfo ai : added) {                                                               
3096                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3097                 }                                                                                        
3098             }                                                                                            
3099                                                                                                          
3100             if (modified != null) {                                                                      
3101                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
3102                 for (AppInfo ai : modified) {                                                            
3103                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3104                 }                                                                                        
3105                                                                                                          
3106                 mHandler.post(new Runnable() {                                                           
3107                     public void run() {                                                                  
3108                         Callbacks cb = getCallback();                                                    
3109                         if (callbacks == cb && cb != null) {                                             
3110                             callbacks.bindAppsUpdated(modifiedFinal);                                    
3111                         }                                                                                
3112                     }                                                                                    
3113                 });                                                                                      
3114             }                                                                                            
3115                                                                                                          
3116             // Update shortcut infos                                                                     
3117             if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                     
3118                 final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();          
3119                 final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();          
3120                 final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>(); 
3121                                                                                                          
3122                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));               
3123                 synchronized (sBgLock) {                                                                 
3124                     for (ItemInfo info : sBgItemsIdMap.values()) {                                       
3125                         if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                   
3126                             ShortcutInfo si = (ShortcutInfo) info;                                       
3127                             boolean infoUpdated = false;                                                 
3128                             boolean shortcutUpdated = false;                                             
3129                                                                                                          
3130                             // Update shortcuts which use iconResource.                                  
3131                             if ((si.iconResource != null)                                                
3132                                     && packageSet.contains(si.iconResource.packageName)) {               
3133                                 Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,    
3134                                         si.iconResource.resourceName, mIconCache, context);              
3135                                 if (icon != null) {                                                      
3136                                     si.setIcon(icon);                                                    
3137                                     si.usingFallbackIcon = false;                                        
3138                                     infoUpdated = true;                                                  
3139                                 }                                                                        
3140                             }                                                                            
3141                                                                                                          
3142                             ComponentName cn = si.getTargetComponent();                                  
3143                             if (cn != null && packageSet.contains(cn.getPackageName())) {                
3144                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);                            
3145                                                                                                          
3146                                 if (si.isPromise()) {                                                    
3147                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {           
3148                                         // Auto install icon                                             
3149                                         PackageManager pm = context.getPackageManager();                 
3150                                         ResolveInfo matched = pm.resolveActivity(                        
3151                                                 new Intent(Intent.ACTION_MAIN)                           
3152                                                 .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER), 
3153                                                 PackageManager.MATCH_DEFAULT_ONLY);                      
3154                                         if (matched == null) {                                           
3155                                             // Try to find the best match activity.                      
3156                                             Intent intent = pm.getLaunchIntentForPackage(                
3157                                                     cn.getPackageName());                                
3158                                             if (intent != null) {                                        
3159                                                 cn = intent.getComponent();                              
3160                                                 appInfo = addedOrUpdatedApps.get(cn);                    
3161                                             }                                                            
3162                                                                                                          
3163                                             if ((intent == null) || (appInfo == null)) {                 
3164                                                 removedShortcuts.add(si);                                
3165                                                 continue;                                                
3166                                             }                                                            
3167                                             si.promisedIntent = intent;                                  
3168                                         }                                                                
3169                                     }                                                                    
3170                                                                                                          
3171                                     // Restore the shortcut.                                             
3172                                     si.intent = si.promisedIntent;                                       
3173                                     si.promisedIntent = null;                                            
3174                                     si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                        
3175                                             & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                         
3176                                             & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                 
3177                                                                                                          
3178                                     infoUpdated = true;                                                  
3179                                     si.updateIcon(mIconCache);                                           
3180                                 }                                                                        
3181                                                                                                          
3182                                 if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())  
3183                                         && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATIO🔵
3184                                     si.updateIcon(mIconCache);                                           
3185                                     si.title = appInfo.title.toString();                                 
3186                                     si.contentDescription = appInfo.contentDescription;                  
3187                                     infoUpdated = true;                                                  
3188                                 }                                                                        
3189                                                                                                          
3190                                 if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {   
3191                                     // Since package was just updated, the target must be available now. 
3192                                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;          
3193                                     shortcutUpdated = true;                                              
3194                                 }                                                                        
3195                             }                                                                            
3196                                                                                                          
3197                             if (infoUpdated || shortcutUpdated) {                                        
3198                                 updatedShortcuts.add(si);                                                
3199                             }                                                                            
3200                             if (infoUpdated) {                                                           
3201                                 updateItemInDatabase(context, si);                                       
3202                             }                                                                            
3203                         } else if (info instanceof LauncherAppWidgetInfo) {                              
3204                             LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;             
3205                             if (mUser.equals(widgetInfo.user)                                            
3206                                     && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_🔵
3207                                     && packageSet.contains(widgetInfo.providerName.getPackageName())) {  
3208                                 widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READ🔵
3209                                 widgets.add(widgetInfo);                                                 
3210                                 updateItemInDatabase(context, widgetInfo);                               
3211                             }                                                                            
3212                         }                                                                                
3213                     }                                                                                    
3214                 }                                                                                        
3215                                                                                                          
3216                 if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                        
3217                     mHandler.post(new Runnable() {                                                       
3218                                                                                                          
3219                         public void run() {                                                              
3220                             Callbacks cb = getCallback();                                                
3221                             if (callbacks == cb && cb != null) {                                         
3222                                 callbacks.bindShortcutsChanged(                                          
3223                                         updatedShortcuts, removedShortcuts, mUser);                      
3224                             }                                                                            
3225                         }                                                                                
3226                     });                                                                                  
3227                     if (!removedShortcuts.isEmpty()) {                                                   
3228                         deleteItemsFromDatabase(context, removedShortcuts);                              
3229                     }                                                                                    
3230                 }                                                                                        
3231                 if (!widgets.isEmpty()) {                                                                
3232                     mHandler.post(new Runnable() {                                                       
3233                         public void run() {                                                              
3234                             Callbacks cb = getCallback();                                                
3235                             if (callbacks == cb && cb != null) {                                         
3236                                 callbacks.bindWidgetsRestored(widgets);                                  
3237                             }                                                                            
3238                         }                                                                                
3239                     });                                                                                  
3240                 }                                                                                        
3241             }                                                                                            
3242                                                                                                          
3243             final ArrayList<String> removedPackageNames =                                                
3244                     new ArrayList<String>();                                                             
3245             if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                             
3246                 // Mark all packages in the broadcast to be removed                                      
3247                 removedPackageNames.addAll(Arrays.asList(packages));                                     
3248             } else if (mOp == OP_UPDATE) {                                                               
3249                 // Mark disabled packages in the broadcast to be removed                                 
3250                 for (int i=0; i<N; i++) {                                                                
3251                     if (isPackageDisabled(context, packages[i], mUser)) {                                
3252                         removedPackageNames.add(packages[i]);                                            
3253                     }                                                                                    
3254                 }                                                                                        
3255             }                                                                                            
3256                                                                                                          
3257             if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                              
3258                 final int removeReason;                                                                  
3259                 if (mOp == OP_UNAVAILABLE) {                                                             
3260                     removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                             
3261                 } else {                                                                                 
3262                     // Remove all the components associated with this package                            
3263                     for (String pn : removedPackageNames) {                                              
3264                         deletePackageFromDatabase(context, pn, mUser);                                   
3265                     }                                                                                    
3266                     // Remove all the specific components                                                
3267                     for (AppInfo a : removedApps) {                                                      
3268                         ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); 
3269                         deleteItemsFromDatabase(context, infos);                                         
3270                     }                                                                                    
3271                     removeReason = 0;                                                                    
3272                 }                                                                                        
3273                                                                                                          
3274                 // Remove any queued items from the install queue                                        
3275                 InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);     
3276                 // Call the components-removed callback                                                  
3277                 mHandler.post(new Runnable() {                                                           
3278                     public void run() {                                                                  
3279                         Callbacks cb = getCallback();                                                    
3280                         if (callbacks == cb && cb != null) {                                             
3281                             callbacks.bindComponentsRemoved(                                             
3282                                     removedPackageNames, removedApps, mUser, removeReason);              
3283                         }                                                                                
3284                     }                                                                                    
3285                 });                                                                                      
3286             }                                                                                            
3287                                                                                                          
3288             final ArrayList<Object> widgetsAndShortcuts =                                                
3289                     getSortedWidgetsAndShortcuts(context);                                               
3290             mHandler.post(new Runnable() {                                                               
3291                 @Override                                                                                
3292                 public void run() {                                                                      
3293                     Callbacks cb = getCallback();                                                        
3294                     if (callbacks == cb && cb != null) {                                                 
3295                         callbacks.bindPackagesUpdated(widgetsAndShortcuts);                              
3296                     }                                                                                    
3297                 }                                                                                        
3298             });                                                                                          
3299                                                                                                          
3300             // Write all the logs to disk                                                                
3301             mHandler.post(new Runnable() {                                                               
3302                 public void run() {                                                                      
3303                     Callbacks cb = getCallback();                                                        
3304                     if (callbacks == cb && cb != null) {                                                 
3305                         callbacks.dumpLogsToLocalData();                                                 
3306                     }                                                                                    
3307                 }                                                                                        
3308             });                                                                                          
3309         }                                                                                                
3310     }                                                                                                    
3311                                                                                                          
3312     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context) {              
3313         synchronized (sBgLock) {                                                                         
3314             if (sBgWidgetProviders != null && !sWidgetProvidersDirty) {                                  
3315                 return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());        
3316             }                                                                                            
3317             sBgWidgetProviders = new HashMap<ComponentName, LauncherAppWidgetProviderInfo>();            
3318             List<AppWidgetProviderInfo> widgets =                                                        
3319                     AppWidgetManagerCompat.getInstance(context).getAllProviders();                       
3320             LauncherAppWidgetProviderInfo info;                                                          
3321             for (AppWidgetProviderInfo pInfo : widgets) {                                                
3322                 info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                   
3323                 sBgWidgetProviders.put(info.provider, info);                                             
3324             }                                                                                            
3325                                                                                                          
3326             Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();         
3327             for (CustomAppWidget widget : customWidgets) {                                               
3328                 info = new LauncherAppWidgetProviderInfo(context, widget);                               
3329                 sBgWidgetProviders.put(info.provider, info);                                             
3330             }                                                                                            
3331             sWidgetProvidersDirty = false;                                                               
3332             return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());            
3333         }                                                                                                
3334     }                                                                                                    
3335                                                                                                          
3336     public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {       
3337         synchronized (sBgLock) {                                                                         
3338             if (sBgWidgetProviders == null) {                                                            
3339                 getWidgetProviders(ctx);                                                                 
3340             }                                                                                            
3341             return sBgWidgetProviders.get(name);                                                         
3342         }                                                                                                
3343     }                                                                                                    
3344                                                                                                          
3345     // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                     
3346     public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                      
3347         PackageManager packageManager = context.getPackageManager();                                     
3348         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3349         widgetsAndShortcuts.addAll(getWidgetProviders(context));                                         
3350         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3351         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3352         Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));             
3353         return widgetsAndShortcuts;                                                                      
3354     }                                                                                                    
3355                                                                                                          
3356     private static boolean isPackageDisabled(Context context, String packageName,                        
3357             UserHandleCompat user) {                                                                     
3358         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3359         return !launcherApps.isPackageEnabledForProfile(packageName, user);                              
3360     }                                                                                                    
3361                                                                                                          
3362     public static boolean isValidPackageActivity(Context context, ComponentName cn,                      
3363             UserHandleCompat user) {                                                                     
3364         if (cn == null) {                                                                                
3365             return false;                                                                                
3366         }                                                                                                
3367         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3368         if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                       
3369             return false;                                                                                
3370         }                                                                                                
3371         return launcherApps.isActivityEnabledForProfile(cn, user);                                       
3372     }                                                                                                    
3373                                                                                                          
3374     public static boolean isValidPackage(Context context, String packageName,                            
3375             UserHandleCompat user) {                                                                     
3376         if (packageName == null) {                                                                       
3377             return false;                                                                                
3378         }                                                                                                
3379         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3380         return launcherApps.isPackageEnabledForProfile(packageName, user);                               
3381     }                                                                                                    
3382                                                                                                          
3383     /**                                                                                                  
3384      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3385      * to a package that is not yet installed on the system.                                             
3386      */                                                                                                  
3387     public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,                
3388             int promiseType) {                                                                           
3389         final ShortcutInfo info = new ShortcutInfo();                                                    
3390         info.user = UserHandleCompat.myUserHandle();                                                     
3391         mIconCache.getTitleAndIcon(info, intent, info.user);                                             
3392                                                                                                          
3393         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                      
3394             String title = (cursor != null) ? cursor.getString(titleIndex) : null;                       
3395             if (!TextUtils.isEmpty(title)) {                                                             
3396                 info.title = title;                                                                      
3397             }                                                                                            
3398             info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                               
3399         } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                            
3400             if (TextUtils.isEmpty(info.title)) {                                                         
3401                 info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                       
3402             }                                                                                            
3403             info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                             
3404         } else {                                                                                         
3405             throw new InvalidParameterException("Invalid restoreType " + promiseType);                   
3406         }                                                                                                
3407                                                                                                          
3408         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3409                 info.title.toString(), info.user);                                                       
3410         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3411         info.promisedIntent = intent;                                                                    
3412         return info;                                                                                     
3413     }                                                                                                    
3414                                                                                                          
3415     /**                                                                                                  
3416      * Make an Intent object for a restored application or shortcut item that points                     
3417      * to the market page for the item.                                                                  
3418      */                                                                                                  
3419     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                     
3420         ComponentName componentName = intent.getComponent();                                             
3421         return getMarketIntent(componentName.getPackageName());                                          
3422     }                                                                                                    
3423                                                                                                          
3424     static Intent getMarketIntent(String packageName) {                                                  
3425         return new Intent(Intent.ACTION_VIEW)                                                            
3426             .setData(new Uri.Builder()                                                                   
3427                 .scheme("market")                                                                        
3428                 .authority("details")                                                                    
3429                 .appendQueryParameter("id", packageName)                                                 
3430                 .build());                                                                               
3431     }                                                                                                    
3432                                                                                                          
3433     /**                                                                                                  
3434      * Make an ShortcutInfo object for a shortcut that is an application.                                
3435      *                                                                                                   
3436      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3437      */                                                                                                  
3438     public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,                        
3439             UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,             
3440             boolean allowMissingTarget) {                                                                
3441         if (user == null) {                                                                              
3442             Log.d(TAG, "Null user found in getShortcutInfo");                                            
3443             return null;                                                                                 
3444         }                                                                                                
3445                                                                                                          
3446         ComponentName componentName = intent.getComponent();                                             
3447         if (componentName == null) {                                                                     
3448             Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                  
3449             return null;                                                                                 
3450         }                                                                                                
3451                                                                                                          
3452         Intent newIntent = new Intent(intent.getAction(), null);                                         
3453         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3454         newIntent.setComponent(componentName);                                                           
3455         LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                 
3456         if ((lai == null) && !allowMissingTarget) {                                                      
3457             Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                   
3458             return null;                                                                                 
3459         }                                                                                                
3460                                                                                                          
3461         final ShortcutInfo info = new ShortcutInfo();                                                    
3462         mIconCache.getTitleAndIcon(info, componentName, lai, user, false);                               
3463         if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {                     
3464             Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                             
3465             info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                         
3466         }                                                                                                
3467                                                                                                          
3468         // from the db                                                                                   
3469         if (TextUtils.isEmpty(info.title) && c != null) {                                                
3470             info.title =  c.getString(titleIndex);                                                       
3471         }                                                                                                
3472                                                                                                          
3473         // fall back to the class name of the activity                                                   
3474         if (info.title == null) {                                                                        
3475             info.title = componentName.getClassName();                                                   
3476         }                                                                                                
3477                                                                                                          
3478         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3479         info.user = user;                                                                                
3480         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3481                 info.title.toString(), info.user);                                                       
3482         return info;                                                                                     
3483     }                                                                                                    
3484                                                                                                          
3485     static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                               
3486             ItemInfoFilter f) {                                                                          
3487         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3488         for (ItemInfo i : infos) {                                                                       
3489             if (i instanceof ShortcutInfo) {                                                             
3490                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3491                 ComponentName cn = info.getTargetComponent();                                            
3492                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3493                     filtered.add(info);                                                                  
3494                 }                                                                                        
3495             } else if (i instanceof FolderInfo) {                                                        
3496                 FolderInfo info = (FolderInfo) i;                                                        
3497                 for (ShortcutInfo s : info.contents) {                                                   
3498                     ComponentName cn = s.getTargetComponent();                                           
3499                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3500                         filtered.add(s);                                                                 
3501                     }                                                                                    
3502                 }                                                                                        
3503             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3504                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3505                 ComponentName cn = info.providerName;                                                    
3506                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3507                     filtered.add(info);                                                                  
3508                 }                                                                                        
3509             }                                                                                            
3510         }                                                                                                
3511         return new ArrayList<ItemInfo>(filtered);                                                        
3512     }                                                                                                    
3513                                                                                                          
3514     private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                   
3515             final UserHandleCompat user) {                                                               
3516         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3517             @Override                                                                                    
3518             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3519                 if (info.user == null) {                                                                 
3520                     return cn.equals(cname);                                                             
3521                 } else {                                                                                 
3522                     return cn.equals(cname) && info.user.equals(user);                                   
3523                 }                                                                                        
3524             }                                                                                            
3525         };                                                                                               
3526         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3527     }                                                                                                    
3528                                                                                                          
3529     /**                                                                                                  
3530      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3531      */                                                                                                  
3532     private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                      
3533             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,               
3534             int titleIndex) {                                                                            
3535                                                                                                          
3536         Bitmap icon = null;                                                                              
3537         final ShortcutInfo info = new ShortcutInfo();                                                    
3538         // Non-app shortcuts are only supported for current user.                                        
3539         info.user = UserHandleCompat.myUserHandle();                                                     
3540         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3541                                                                                                          
3542         // TODO: If there's an explicit component and we can't install that, delete it.                  
3543                                                                                                          
3544         info.title = c.getString(titleIndex);                                                            
3545                                                                                                          
3546         int iconType = c.getInt(iconTypeIndex);                                                          
3547         switch (iconType) {                                                                              
3548         case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                              
3549             String packageName = c.getString(iconPackageIndex);                                          
3550             String resourceName = c.getString(iconResourceIndex);                                        
3551             info.customIcon = false;                                                                     
3552             // the resource                                                                              
3553             icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);           
3554             // the db                                                                                    
3555             if (icon == null) {                                                                          
3556                 icon = Utilities.createIconBitmap(c, iconIndex, context);                                
3557             }                                                                                            
3558             // the fallback icon                                                                         
3559             if (icon == null) {                                                                          
3560                 icon = mIconCache.getDefaultIcon(info.user);                                             
3561                 info.usingFallbackIcon = true;                                                           
3562             }                                                                                            
3563             break;                                                                                       
3564         case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                
3565             icon = Utilities.createIconBitmap(c, iconIndex, context);                                    
3566             if (icon == null) {                                                                          
3567                 icon = mIconCache.getDefaultIcon(info.user);                                             
3568                 info.customIcon = false;                                                                 
3569                 info.usingFallbackIcon = true;                                                           
3570             } else {                                                                                     
3571                 info.customIcon = true;                                                                  
3572             }                                                                                            
3573             break;                                                                                       
3574         default:                                                                                         
3575             icon = mIconCache.getDefaultIcon(info.user);                                                 
3576             info.usingFallbackIcon = true;                                                               
3577             info.customIcon = false;                                                                     
3578             break;                                                                                       
3579         }                                                                                                
3580         info.setIcon(icon);                                                                              
3581         return info;                                                                                     
3582     }                                                                                                    
3583                                                                                                          
3584     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                  
3585         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3586         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3587         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3588                                                                                                          
3589         if (intent == null) {                                                                            
3590             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3591             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3592             return null;                                                                                 
3593         }                                                                                                
3594                                                                                                          
3595         Bitmap icon = null;                                                                              
3596         boolean customIcon = false;                                                                      
3597         ShortcutIconResource iconResource = null;                                                        
3598                                                                                                          
3599         if (bitmap instanceof Bitmap) {                                                                  
3600             icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                 
3601             customIcon = true;                                                                           
3602         } else {                                                                                         
3603             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3604             if (extra instanceof ShortcutIconResource) {                                                 
3605                 iconResource = (ShortcutIconResource) extra;                                             
3606                 icon = Utilities.createIconBitmap(iconResource.packageName,                              
3607                         iconResource.resourceName, mIconCache, context);                                 
3608             }                                                                                            
3609         }                                                                                                
3610                                                                                                          
3611         final ShortcutInfo info = new ShortcutInfo();                                                    
3612                                                                                                          
3613         // Only support intents for current user for now. Intents sent from other                        
3614         // users wouldn't get here without intent forwarding anyway.                                     
3615         info.user = UserHandleCompat.myUserHandle();                                                     
3616         if (icon == null) {                                                                              
3617             icon = mIconCache.getDefaultIcon(info.user);                                                 
3618             info.usingFallbackIcon = true;                                                               
3619         }                                                                                                
3620         info.setIcon(icon);                                                                              
3621                                                                                                          
3622         info.title = name;                                                                               
3623         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3624                 info.title.toString(), info.user);                                                       
3625         info.intent = intent;                                                                            
3626         info.customIcon = customIcon;                                                                    
3627         info.iconResource = iconResource;                                                                
3628                                                                                                          
3629         return info;                                                                                     
3630     }                                                                                                    
3631                                                                                                          
3632     /**                                                                                                  
3633      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3634      * or make a new one.                                                                                
3635      */                                                                                                  
3636     private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {             
3637         // See if a placeholder was created for us already                                               
3638         FolderInfo folderInfo = folders.get(id);                                                         
3639         if (folderInfo == null) {                                                                        
3640             // No placeholder -- create a new instance                                                   
3641             folderInfo = new FolderInfo();                                                               
3642             folders.put(id, folderInfo);                                                                 
3643         }                                                                                                
3644         return folderInfo;                                                                               
3645     }                                                                                                    
3646                                                                                                          
3647     public static final Comparator<AppInfo> getAppNameComparator() {                                     
3648         final Collator collator = Collator.getInstance();                                                
3649         return new Comparator<AppInfo>() {                                                               
3650             public final int compare(AppInfo a, AppInfo b) {                                             
3651                 if (a.user.equals(b.user)) {                                                             
3652                     int result = collator.compare(a.title.toString().trim(),                             
3653                             b.title.toString().trim());                                                  
3654                     if (result == 0) {                                                                   
3655                         result = a.componentName.compareTo(b.componentName);                             
3656                     }                                                                                    
3657                     return result;                                                                       
3658                 } else {                                                                                 
3659                     // TODO Need to figure out rules for sorting                                         
3660                     // profiles, this puts work second.                                                  
3661                     return a.user.toString().compareTo(b.user.toString());                               
3662                 }                                                                                        
3663             }                                                                                            
3664         };                                                                                               
3665     }                                                                                                    
3666     public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                  
3667             = new Comparator<AppInfo>() {                                                                
3668         public final int compare(AppInfo a, AppInfo b) {                                                 
3669             if (a.firstInstallTime < b.firstInstallTime) return 1;                                       
3670             if (a.firstInstallTime > b.firstInstallTime) return -1;                                      
3671             return 0;                                                                                    
3672         }                                                                                                
3673     };                                                                                                   
3674     static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                             
3675         if (info.activityInfo != null) {                                                                 
3676             return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);             
3677         } else {                                                                                         
3678             return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);               
3679         }                                                                                                
3680     }                                                                                                    
3681                                                                                                          
3682     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                  
3683         private final AppWidgetManagerCompat mManager;                                                   
3684         private final PackageManager mPackageManager;                                                    
3685         private final HashMap<Object, String> mLabelCache;                                               
3686         private final Collator mCollator;                                                                
3687                                                                                                          
3688         WidgetAndShortcutNameComparator(Context context) {                                               
3689             mManager = AppWidgetManagerCompat.getInstance(context);                                      
3690             mPackageManager = context.getPackageManager();                                               
3691             mLabelCache = new HashMap<Object, String>();                                                 
3692             mCollator = Collator.getInstance();                                                          
3693         }                                                                                                
3694         public final int compare(Object a, Object b) {                                                   
3695             String labelA, labelB;                                                                       
3696             if (mLabelCache.containsKey(a)) {                                                            
3697                 labelA = mLabelCache.get(a);                                                             
3698             } else {                                                                                     
3699                 labelA = (a instanceof LauncherAppWidgetProviderInfo)                                    
3700                         ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a)                          
3701                         : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                
3702                 mLabelCache.put(a, labelA);                                                              
3703             }                                                                                            
3704             if (mLabelCache.containsKey(b)) {                                                            
3705                 labelB = mLabelCache.get(b);                                                             
3706             } else {                                                                                     
3707                 labelB = (b instanceof LauncherAppWidgetProviderInfo)                                    
3708                         ? mManager.loadLabel((LauncherAppWidgetProviderInfo) b)                          
3709                         : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                
3710                 mLabelCache.put(b, labelB);                                                              
3711             }                                                                                            
3712             return mCollator.compare(labelA, labelB);                                                    
3713         }                                                                                                
3714     };                                                                                                   
3715                                                                                                          
3716     static boolean isValidProvider(AppWidgetProviderInfo provider) {                                     
3717         return (provider != null) && (provider.provider != null)                                         
3718                 && (provider.provider.getPackageName() != null);                                         
3719     }                                                                                                    
3720                                                                                                          
3721     public void dumpState() {                                                                            
3722         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3723         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3724         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3725         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3726         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3727         if (mLoaderTask != null) {                                                                       
3728             mLoaderTask.dumpState();                                                                     
3729         } else {                                                                                         
3730             Log.d(TAG, "mLoaderTask=null");                                                              
3731         }                                                                                                
3732     }                                                                                                    
3733                                                                                                          
3734     public Callbacks getCallback() {                                                                     
3735         return mCallbacks != null ? mCallbacks.get() : null;                                             
3736     }                                                                                                    
3737 }                                                                                                        
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.app.SearchManager;                                                                        
  20 import android.appwidget.AppWidgetProviderInfo;                                                          
  21 import android.content.BroadcastReceiver;                                                                
  22 import android.content.ComponentName;                                                                    
  23 import android.content.ContentProviderClient;                                                            
  24 import android.content.ContentProviderOperation;                                                         
  25 import android.content.ContentResolver;                                                                  
  26 import android.content.ContentValues;                                                                    
  27 import android.content.Context;                                                                          
  28 import android.content.Intent;                                                                           
  29 import android.content.Intent.ShortcutIconResource;                                                      
  30 import android.content.IntentFilter;                                                                     
  31 import android.content.SharedPreferences;                                                                
  32 import android.content.pm.PackageManager;                                                                
  33 import android.content.pm.ProviderInfo;                                                                  
  34 import android.content.pm.ResolveInfo;                                                                   
  35 import android.content.res.Configuration;                                                                
  36 import android.content.res.Resources;                                                                    
  37 import android.database.Cursor;                                                                          
  38 import android.graphics.Bitmap;                                                                          
  39 import android.graphics.Rect;                                                                            
  40 import android.net.Uri;                                                                                  
  41 import android.os.Environment;                                                                           
  42 import android.os.Handler;                                                                               
  43 import android.os.HandlerThread;                                                                         
  44 import android.os.Parcelable;                                                                            
  45 import android.os.Process;                                                                               
  46 import android.os.RemoteException;                                                                       
  47 import android.os.SystemClock;                                                                           
  48 import android.provider.BaseColumns;                                                                     
  49 import android.text.TextUtils;                                                                           
  50 import android.util.Log;                                                                                 
  51 import android.util.LongSparseArray;                                                                     
  52 import android.util.Pair;                                                                                
  53                                                                                                          
  54 import com.android.launcher3.compat.AppWidgetManagerCompat;                                              
  55 import com.android.launcher3.compat.LauncherActivityInfoCompat;                                          
  56 import com.android.launcher3.compat.LauncherAppsCompat;                                                  
  57 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  58 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  59 import com.android.launcher3.compat.UserHandleCompat;                                                    
  60 import com.android.launcher3.compat.UserManagerCompat;                                                   
  61                                                                                                          
  62 import java.lang.ref.WeakReference;                                                                      
  63 import java.net.URISyntaxException;                                                                      
  64 import java.security.InvalidParameterException;                                                          
  65 import java.text.Collator;                                                                               
  66 import java.util.ArrayList;                                                                              
  67 import java.util.Arrays;                                                                                 
  68 import java.util.Collection;                                                                             
  69 import java.util.Collections;                                                                            
  70 import java.util.Comparator;                                                                             
  71 import java.util.HashMap;                                                                                
  72 import java.util.HashSet;                                                                                
  73 import java.util.Iterator;                                                                               
  74 import java.util.List;                                                                                   
  75 import java.util.Map.Entry;                                                                              
  76 import java.util.Set;                                                                                    
  77                                                                                                          
  78 /**                                                                                                      
  79  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  80  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  81  * for the Launcher.                                                                                     
  82  */                                                                                                      
  83 public class LauncherModel extends BroadcastReceiver                                                     
  84         implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                      
  85     static final boolean DEBUG_LOADERS = false;                                                          
  86     private static final boolean DEBUG_RECEIVER = false;                                                 
  87     private static final boolean REMOVE_UNRESTORED_ICONS = true;                                         
  88     private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                  
  89                                                                                                          
  90     static final String TAG = "Launcher.Model";                                                          
  91                                                                                                          
  92     public static final int LOADER_FLAG_NONE = 0;                                                        
  93     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  94     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  95                                                                                                          
  96     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  97     private static final long INVALID_SCREEN_ID = -1L;                                                   
  98                                                                                                          
  99     private final boolean mAppsCanBeOnRemoveableStorage;                                                 
 100     private final boolean mOldContentProviderExists;                                                     
 101                                                                                                          
 102     private final LauncherAppState mApp;                                                                 
 103     private final Object mLock = new Object();                                                           
 104     private DeferredHandler mHandler = new DeferredHandler();                                            
 105     private LoaderTask mLoaderTask;                                                                      
 106     private boolean mIsLoaderTaskRunning;                                                                
 107                                                                                                          
 108     /**                                                                                                  
 109      * Maintain a set of packages per user, for which we added a shortcut on the workspace.              
 110      */                                                                                                  
 111     private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";    
 112                                                                                                          
 113     // Specific runnable types that are run on the main thread deferred handler, this allows us to       
 114     // clear all queued binding runnables when the Launcher activity is destroyed.                       
 115     private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                            
 116     private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                           
 117                                                                                                          
 118     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                    
 119                                                                                                          
 120     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");             
 121     static {                                                                                             
 122         sWorkerThread.start();                                                                           
 123     }                                                                                                    
 124     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                       
 125                                                                                                          
 126     // We start off with everything not loaded.  After that, we assume that                              
 127     // our monitoring of the package manager provides all updates and we never                           
 128     // need to do a requery.  These are only ever touched from the loader thread.                        
 129     private boolean mWorkspaceLoaded;                                                                    
 130     private boolean mAllAppsLoaded;                                                                      
 131                                                                                                          
 132     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 133     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 134     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 135     // a normal load, we also clear this set of Runnables.                                               
 136     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 137                                                                                                          
 138     private WeakReference<Callbacks> mCallbacks;                                                         
 139                                                                                                          
 140     // < only access in worker thread >                                                                  
 141     AllAppsList mBgAllAppsList;                                                                          
 142                                                                                                          
 143     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 144     // other locks, this one can generally be held long-term because we never expect any of these        
 145     // static data structures to be referenced outside of the worker thread except on the first          
 146     // load after configuration change.                                                                  
 147     static final Object sBgLock = new Object();                                                          
 148                                                                                                          
 149     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 150     // LauncherModel to their ids                                                                        
 151     static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                  
 152                                                                                                          
 153     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 154     //       created by LauncherModel that are directly on the home screen (however, no widgets or       
 155     //       shortcuts within folders).                                                                  
 156     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 157                                                                                                          
 158     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 159     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 160         new ArrayList<LauncherAppWidgetInfo>();                                                          
 161                                                                                                          
 162     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 163     static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                 
 164                                                                                                          
 165     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 166     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 167                                                                                                          
 168     // sBgWidgetProviders is the set of widget providers including custom internal widgets               
 169     public static HashMap<ComponentName, LauncherAppWidgetProviderInfo> sBgWidgetProviders;              
 170     public static boolean sWidgetProvidersDirty;                                                         
 171                                                                                                          
 172     // sPendingPackages is a set of packages which could be on sdcard and are not available yet          
 173     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                           
 174             new HashMap<UserHandleCompat, HashSet<String>>();                                            
 175                                                                                                          
 176     // </ only access in worker thread >                                                                 
 177                                                                                                          
 178     private IconCache mIconCache;                                                                        
 179                                                                                                          
 180     protected int mPreviousConfigMcc;                                                                    
 181                                                                                                          
 182     private final LauncherAppsCompat mLauncherApps;                                                      
 183     private final UserManagerCompat mUserManager;                                                        
 184                                                                                                          
 185     public interface Callbacks {                                                                         
 186         public boolean setLoadOnResume();                                                                
 187         public int getCurrentWorkspaceScreen();                                                          
 188         public void startBinding();                                                                      
 189         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 190                               boolean forceAnimateIcons);                                                
 191         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 192         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 193         public void bindFolders(HashMap<Long,FolderInfo> folders);                                       
 194         public void finishBindingItems();                                                                
 195         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 196         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 197         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 198                                   ArrayList<ItemInfo> addNotAnimated,                                    
 199                                   ArrayList<ItemInfo> addAnimated,                                       
 200                                   ArrayList<AppInfo> addedApps);                                         
 201         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 202         public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                
 203                 ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                 
 204         public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                       
 205         public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);                       
 206         public void updatePackageBadge(String packageName);                                              
 207         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 208                         ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                 
 209         public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                          
 210         public void bindSearchablesChanged();                                                            
 211         public boolean isAllAppsButtonRank(int rank);                                                    
 212         public void onPageBoundSynchronously(int page);                                                  
 213         public void dumpLogsToLocalData();                                                               
 214         public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,           
 215                 int[] cell, int spanX, int spanY);                                                       
 216     }                                                                                                    
 217                                                                                                          
 218     public interface ItemInfoFilter {                                                                    
 219         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                     
 220     }                                                                                                    
 221                                                                                                          
 222     public interface ScreenPosProvider {                                                                 
 223         int getScreenIndex(ArrayList<Long> screenIDs);                                                   
 224     }                                                                                                    
 225                                                                                                          
 226     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 227         Context context = app.getContext();                                                              
 228                                                                                                          
 229         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 230         String oldProvider = context.getString(R.string.old_launcher_provider_uri);                      
 231         // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different               
 232         // resource string.                                                                              
 233         String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                
 234         ProviderInfo providerInfo =                                                                      
 235                 context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                
 236         ProviderInfo redirectProvider =                                                                  
 237                 context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                
 238                                                                                                          
 239         Log.d(TAG, "Old launcher provider: " + oldProvider);                                             
 240         mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                
 241                                                                                                          
 242         if (mOldContentProviderExists) {                                                                 
 243             Log.d(TAG, "Old launcher provider exists.");                                                 
 244         } else {                                                                                         
 245             Log.d(TAG, "Old launcher provider does not exist.");                                         
 246         }                                                                                                
 247                                                                                                          
 248         mApp = app;                                                                                      
 249         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 250         mIconCache = iconCache;                                                                          
 251                                                                                                          
 252         final Resources res = context.getResources();                                                    
 253         Configuration config = res.getConfiguration();                                                   
 254         mPreviousConfigMcc = config.mcc;                                                                 
 255         mLauncherApps = LauncherAppsCompat.getInstance(context);                                         
 256         mUserManager = UserManagerCompat.getInstance(context);                                           
 257     }                                                                                                    
 258                                                                                                          
 259     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 260      * posted on the main thread handler. */                                                             
 261     private void runOnMainThread(Runnable r) {                                                           
 262         runOnMainThread(r, 0);                                                                           
 263     }                                                                                                    
 264     private void runOnMainThread(Runnable r, int type) {                                                 
 265         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 266             // If we are on the worker thread, post onto the main handler                                
 267             mHandler.post(r);                                                                            
 268         } else {                                                                                         
 269             r.run();                                                                                     
 270         }                                                                                                
 271     }                                                                                                    
 272                                                                                                          
 273     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 274      * posted on the worker thread handler. */                                                           
 275     private static void runOnWorkerThread(Runnable r) {                                                  
 276         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 277             r.run();                                                                                     
 278         } else {                                                                                         
 279             // If we are not on the worker thread, then post to the worker handler                       
 280             sWorker.post(r);                                                                             
 281         }                                                                                                
 282     }                                                                                                    
 283                                                                                                          
 284     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 285         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 286     }                                                                                                    
 287                                                                                                          
 288     public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                       
 289         // Process the updated package state                                                             
 290         Runnable r = new Runnable() {                                                                    
 291             public void run() {                                                                          
 292                 Callbacks callbacks = getCallback();                                                     
 293                 if (callbacks != null) {                                                                 
 294                     callbacks.updatePackageState(installInfo);                                           
 295                 }                                                                                        
 296             }                                                                                            
 297         };                                                                                               
 298         mHandler.post(r);                                                                                
 299     }                                                                                                    
 300                                                                                                          
 301     public void updatePackageBadge(final String packageName) {                                           
 302         // Process the updated package badge                                                             
 303         Runnable r = new Runnable() {                                                                    
 304             public void run() {                                                                          
 305                 Callbacks callbacks = getCallback();                                                     
 306                 if (callbacks != null) {                                                                 
 307                     callbacks.updatePackageBadge(packageName);                                           
 308                 }                                                                                        
 309             }                                                                                            
 310         };                                                                                               
 311         mHandler.post(r);                                                                                
 312     }                                                                                                    
 313                                                                                                          
 314     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 315         final Callbacks callbacks = getCallback();                                                       
 316                                                                                                          
 317         if (allAppsApps == null) {                                                                       
 318             throw new RuntimeException("allAppsApps must not be null");                                  
 319         }                                                                                                
 320         if (allAppsApps.isEmpty()) {                                                                     
 321             return;                                                                                      
 322         }                                                                                                
 323                                                                                                          
 324         // Process the newly added applications and add them to the database first                       
 325         Runnable r = new Runnable() {                                                                    
 326             public void run() {                                                                          
 327                 runOnMainThread(new Runnable() {                                                         
 328                     public void run() {                                                                  
 329                         Callbacks cb = getCallback();                                                    
 330                         if (callbacks == cb && cb != null) {                                             
 331                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 332                         }                                                                                
 333                     }                                                                                    
 334                 });                                                                                      
 335             }                                                                                            
 336         };                                                                                               
 337         runOnWorkerThread(r);                                                                            
 338     }                                                                                                    
 339                                                                                                          
 340     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 341             final ArrayList<ItemInfo> workspaceApps) {                                                   
 342         addAndBindAddedWorkspaceApps(context, workspaceApps,                                             
 343                 new ScreenPosProvider() {                                                                
 344                                                                                                          
 345                     @Override                                                                            
 346                     public int getScreenIndex(ArrayList<Long> screenIDs) {                               
 347                         return screenIDs.isEmpty() ? 0 : 1;                                              
 348                     }                                                                                    
 349                 }, 1, false);                                                                            
 350     }                                                                                                    
 351                                                                                                          
 352     private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,               
 353             int[] xy, int spanX, int spanY) {                                                            
 354         LauncherAppState app = LauncherAppState.getInstance();                                           
 355         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 356         final int xCount = (int) grid.numColumns;                                                        
 357         final int yCount = (int) grid.numRows;                                                           
 358         boolean[][] occupied = new boolean[xCount][yCount];                                              
 359         if (occupiedPos != null) {                                                                       
 360             for (Rect r : occupiedPos) {                                                                 
 361                 for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                         
 362                     for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                     
 363                         occupied[x][y] = true;                                                           
 364                     }                                                                                    
 365                 }                                                                                        
 366             }                                                                                            
 367         }                                                                                                
 368         return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                    
 369     }                                                                                                    
 370                                                                                                          
 371     /**                                                                                                  
 372      * Find a position on the screen for the given size or adds a new screen.                            
 373      * @return screenId and the coordinates for the item.                                                
 374      */                                                                                                  
 375     private static Pair<Long, int[]> findSpaceForItem(                                                   
 376             Context context,                                                                             
 377             ScreenPosProvider preferredScreen,                                                           
 378             int fallbackStartScreen,                                                                     
 379             ArrayList<Long> workspaceScreens,                                                            
 380             ArrayList<Long> addedWorkspaceScreensFinal,                                                  
 381             int spanX, int spanY) {                                                                      
 382         // Load position of items which are on the desktop. We can't use sBgItemsIdMap because           
 383         // loadWorkspace() may not have been called.                                                     
 384         final ContentResolver cr = context.getContentResolver();                                         
 385         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 386                 new String[] {                                                                           
 387                     LauncherSettings.Favorites.SCREEN,                                                   
 388                     LauncherSettings.Favorites.CELLX,                                                    
 389                     LauncherSettings.Favorites.CELLY,                                                    
 390                     LauncherSettings.Favorites.SPANX,                                                    
 391                     LauncherSettings.Favorites.SPANY,                                                    
 392                     LauncherSettings.Favorites.CONTAINER                                                 
 393                  },                                                                                      
 394                  "container=?",                                                                          
 395                  new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },        
 396                  null);                                                                                  
 397                                                                                                          
 398         final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);              
 399         final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                
 400         final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                
 401         final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                
 402         final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                
 403         LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();           
 404         try {                                                                                            
 405             while (c.moveToNext()) {                                                                     
 406                 Rect rect = new Rect();                                                                  
 407                 rect.left = c.getInt(cellXIndex);                                                        
 408                 rect.top = c.getInt(cellYIndex);                                                         
 409                 rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                              
 410                 rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                              
 411                                                                                                          
 412                 long screenId = c.getInt(screenIndex);                                                   
 413                 ArrayList<Rect> items = screenItems.get(screenId);                                       
 414                 if (items == null) {                                                                     
 415                     items = new ArrayList<Rect>();                                                       
 416                     screenItems.put(screenId, items);                                                    
 417                 }                                                                                        
 418                 items.add(rect);                                                                         
 419             }                                                                                            
 420         } catch (Exception e) {                                                                          
 421             screenItems.clear();                                                                         
 422         } finally {                                                                                      
 423             c.close();                                                                                   
 424         }                                                                                                
 425                                                                                                          
 426         // Find appropriate space for the item.                                                          
 427         long screenId = 0;                                                                               
 428         int[] cordinates = new int[2];                                                                   
 429         boolean found = false;                                                                           
 430                                                                                                          
 431         int screenCount = workspaceScreens.size();                                                       
 432         // First check the preferred screen.                                                             
 433         int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                     
 434         if (preferredScreenIndex < screenCount) {                                                        
 435             screenId = workspaceScreens.get(preferredScreenIndex);                                       
 436             found = findNextAvailableIconSpaceInScreen(                                                  
 437                     screenItems.get(screenId), cordinates, spanX, spanY);                                
 438         }                                                                                                
 439                                                                                                          
 440         if (!found) {                                                                                    
 441             // Search on any of the screens.                                                             
 442             for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                     
 443                 screenId = workspaceScreens.get(screen);                                                 
 444                 if (findNextAvailableIconSpaceInScreen(                                                  
 445                         screenItems.get(screenId), cordinates, spanX, spanY)) {                          
 446                     // We found a space for it                                                           
 447                     found = true;                                                                        
 448                     break;                                                                               
 449                 }                                                                                        
 450             }                                                                                            
 451         }                                                                                                
 452                                                                                                          
 453         if (!found) {                                                                                    
 454             // Still no position found. Add a new screen to the end.                                     
 455             screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                     
 456                                                                                                          
 457             // Save the screen id for binding in the workspace                                           
 458             workspaceScreens.add(screenId);                                                              
 459             addedWorkspaceScreensFinal.add(screenId);                                                    
 460                                                                                                          
 461             // If we still can't find an empty space, then God help us all!!!                            
 462             if (!findNextAvailableIconSpaceInScreen(                                                     
 463                     screenItems.get(screenId), cordinates, spanX, spanY)) {                              
 464                 throw new RuntimeException("Can't find space to add the item");                          
 465             }                                                                                            
 466         }                                                                                                
 467         return Pair.create(screenId, cordinates);                                                        
 468     }                                                                                                    
 469                                                                                                          
 470     /**                                                                                                  
 471      * Adds the provided items to the workspace.                                                         
 472      * @param preferredScreen the screen where we should try to add the app first                        
 473      * @param fallbackStartScreen the screen to start search for empty space if                          
 474      * preferredScreen is not available.                                                                 
 475      */                                                                                                  
 476     public void addAndBindPendingItem(                                                                   
 477             final Context context,                                                                       
 478             final PendingAddItemInfo addInfo,                                                            
 479             final ScreenPosProvider preferredScreen,                                                     
 480             final int fallbackStartScreen) {                                                             
 481         final Callbacks callbacks = getCallback();                                                       
 482         // Process the newly added applications and add them to the database first                       
 483         Runnable r = new Runnable() {                                                                    
 484             public void run() {                                                                          
 485                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 486                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 487                                                                                                          
 488                 // Find appropriate space for the item.                                                  
 489                 Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                    
 490                         fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,               
 491                         addInfo.spanX,                                                                   
 492                         addInfo.spanY);                                                                  
 493                 final long screenId = coords.first;                                                      
 494                 final int[] cordinates = coords.second;                                                  
 495                                                                                                          
 496                 // Update the workspace screens                                                          
 497                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 498                 runOnMainThread(new Runnable() {                                                         
 499                     public void run() {                                                                  
 500                         Callbacks cb = getCallback();                                                    
 501                         if (callbacks == cb && cb != null) {                                             
 502                             cb.bindAddScreens(addedWorkspaceScreensFinal);                               
 503                             cb.bindAddPendingItem(addInfo,                                               
 504                                     LauncherSettings.Favorites.CONTAINER_DESKTOP,                        
 505                                     screenId, cordinates, addInfo.spanX, addInfo.spanY);                 
 506                         }                                                                                
 507                     }                                                                                    
 508                 });                                                                                      
 509             }                                                                                            
 510         };                                                                                               
 511         runOnWorkerThread(r);                                                                            
 512     }                                                                                                    
 513                                                                                                          
 514     /**                                                                                                  
 515      * Adds the provided items to the workspace.                                                         
 516      * @param preferredScreen the screen where we should try to add the app first                        
 517      * @param fallbackStartScreen the screen to start search for empty space if                          
 518      * preferredScreen is not available.                                                                 
 519      */                                                                                                  
 520     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 521             final ArrayList<ItemInfo> workspaceApps,                                                     
 522             final ScreenPosProvider preferredScreen,                                                     
 523             final int fallbackStartScreen,                                                               
 524             final boolean allowDuplicate) {                                                              
 525         final Callbacks callbacks = getCallback();                                                       
 526         if (workspaceApps.isEmpty()) {                                                                   
 527             return;                                                                                      
 528         }                                                                                                
 529         // Process the newly added applications and add them to the database first                       
 530         Runnable r = new Runnable() {                                                                    
 531             public void run() {                                                                          
 532                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 533                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 534                                                                                                          
 535                 // Get the list of workspace screens.  We need to append to this list and                
 536                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 537                 // called.                                                                               
 538                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 539                 synchronized(sBgLock) {                                                                  
 540                     for (ItemInfo item : workspaceApps) {                                                
 541                         if (!allowDuplicate) {                                                           
 542                             // Short-circuit this logic if the icon exists somewhere on the workspace    
 543                             if (shortcutExists(context, item.title.toString(),                           
 544                                     item.getIntent(), item.user)) {                                      
 545                                 continue;                                                                
 546                             }                                                                            
 547                         }                                                                                
 548                                                                                                          
 549                         // Find appropriate space for the item.                                          
 550                         Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,            
 551                                 fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,       
 552                                 1, 1);                                                                   
 553                         long screenId = coords.first;                                                    
 554                         int[] cordinates = coords.second;                                                
 555                                                                                                          
 556                         ShortcutInfo shortcutInfo;                                                       
 557                         if (item instanceof ShortcutInfo) {                                              
 558                             shortcutInfo = (ShortcutInfo) item;                                          
 559                         } else if (item instanceof AppInfo) {                                            
 560                             shortcutInfo = ((AppInfo) item).makeShortcut();                              
 561                         } else {                                                                         
 562                             throw new RuntimeException("Unexpected info type");                          
 563                         }                                                                                
 564                                                                                                          
 565                         // Add the shortcut to the db                                                    
 566                         addItemToDatabase(context, shortcutInfo,                                         
 567                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 568                                 screenId, cordinates[0], cordinates[1], false);                          
 569                         // Save the ShortcutInfo for binding in the workspace                            
 570                         addedShortcutsFinal.add(shortcutInfo);                                           
 571                     }                                                                                    
 572                 }                                                                                        
 573                                                                                                          
 574                 // Update the workspace screens                                                          
 575                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 576                                                                                                          
 577                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 578                     runOnMainThread(new Runnable() {                                                     
 579                         public void run() {                                                              
 580                             Callbacks cb = getCallback();                                                
 581                             if (callbacks == cb && cb != null) {                                         
 582                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 583                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 584                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 585                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 586                                     long lastScreenId = info.screenId;                                   
 587                                     for (ItemInfo i : addedShortcutsFinal) {                             
 588                                         if (i.screenId == lastScreenId) {                                
 589                                             addAnimated.add(i);                                          
 590                                         } else {                                                         
 591                                             addNotAnimated.add(i);                                       
 592                                         }                                                                
 593                                     }                                                                    
 594                                 }                                                                        
 595                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 596                                         addNotAnimated, addAnimated, null);                              
 597                             }                                                                            
 598                         }                                                                                
 599                     });                                                                                  
 600                 }                                                                                        
 601             }                                                                                            
 602         };                                                                                               
 603         runOnWorkerThread(r);                                                                            
 604     }                                                                                                    
 605                                                                                                          
 606     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 607         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 608             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 609                     "main thread");                                                                      
 610         }                                                                                                
 611                                                                                                          
 612         // Clear any deferred bind runnables                                                             
 613         synchronized (mDeferredBindRunnables) {                                                          
 614             mDeferredBindRunnables.clear();                                                              
 615         }                                                                                                
 616         // Remove any queued bind runnables                                                              
 617         mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                 
 618         // Unbind all the workspace items                                                                
 619         unbindWorkspaceItemsOnMainThread();                                                              
 620     }                                                                                                    
 621                                                                                                          
 622     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 623     void unbindWorkspaceItemsOnMainThread() {                                                            
 624         // Ensure that we don't use the same workspace items data structure on the main thread           
 625         // by making a copy of workspace items first.                                                    
 626         final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                         
 627         final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                             
 628         synchronized (sBgLock) {                                                                         
 629             tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                 
 630             tmpAppWidgets.addAll(sBgAppWidgets);                                                         
 631         }                                                                                                
 632         Runnable r = new Runnable() {                                                                    
 633                 @Override                                                                                
 634                 public void run() {                                                                      
 635                    for (ItemInfo item : tmpWorkspaceItems) {                                             
 636                        item.unbind();                                                                    
 637                    }                                                                                     
 638                    for (ItemInfo item : tmpAppWidgets) {                                                 
 639                        item.unbind();                                                                    
 640                    }                                                                                     
 641                 }                                                                                        
 642             };                                                                                           
 643         runOnMainThread(r);                                                                              
 644     }                                                                                                    
 645                                                                                                          
 646     /**                                                                                                  
 647      * Adds an item to the DB if it was not created previously, or move it to a new                      
 648      * <container, screen, cellX, cellY>                                                                 
 649      */                                                                                                  
 650     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 651             long screenId, int cellX, int cellY) {                                                       
 652         if (item.container == ItemInfo.NO_ID) {                                                          
 653             // From all apps                                                                             
 654             addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                  
 655         } else {                                                                                         
 656             // From somewhere else                                                                       
 657             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 658         }                                                                                                
 659     }                                                                                                    
 660                                                                                                          
 661     static void checkItemInfoLocked(                                                                     
 662             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 663         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 664         if (modelItem != null && item != modelItem) {                                                    
 665             // check all the data is consistent                                                          
 666             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 667                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 668                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 669                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 670                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 671                         modelShortcut.id == shortcut.id &&                                               
 672                         modelShortcut.itemType == shortcut.itemType &&                                   
 673                         modelShortcut.container == shortcut.container &&                                 
 674                         modelShortcut.screenId == shortcut.screenId &&                                   
 675                         modelShortcut.cellX == shortcut.cellX &&                                         
 676                         modelShortcut.cellY == shortcut.cellY &&                                         
 677                         modelShortcut.spanX == shortcut.spanX &&                                         
 678                         modelShortcut.spanY == shortcut.spanY &&                                         
 679                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 680                         (modelShortcut.dropPos != null &&                                                
 681                                 shortcut.dropPos != null &&                                              
 682                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 683                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 684                     // For all intents and purposes, this is the same object                             
 685                     return;                                                                              
 686                 }                                                                                        
 687             }                                                                                            
 688                                                                                                          
 689             // the modelItem needs to match up perfectly with item if our model is                       
 690             // to be consistent with the database-- for now, just require                                
 691             // modelItem == item or the equality check above                                             
 692             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 693                     "modelItem: " +                                                                      
 694                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 695                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 696             RuntimeException e = new RuntimeException(msg);                                              
 697             if (stackTrace != null) {                                                                    
 698                 e.setStackTrace(stackTrace);                                                             
 699             }                                                                                            
 700             throw e;                                                                                     
 701         }                                                                                                
 702     }                                                                                                    
 703                                                                                                          
 704     static void checkItemInfo(final ItemInfo item) {                                                     
 705         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 706         final long itemId = item.id;                                                                     
 707         Runnable r = new Runnable() {                                                                    
 708             public void run() {                                                                          
 709                 synchronized (sBgLock) {                                                                 
 710                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 711                 }                                                                                        
 712             }                                                                                            
 713         };                                                                                               
 714         runOnWorkerThread(r);                                                                            
 715     }                                                                                                    
 716                                                                                                          
 717     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 718             final ItemInfo item, final String callingFunction) {                                         
 719         final long itemId = item.id;                                                                     
 720         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                         
 721         final ContentResolver cr = context.getContentResolver();                                         
 722                                                                                                          
 723         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 724         Runnable r = new Runnable() {                                                                    
 725             public void run() {                                                                          
 726                 cr.update(uri, values, null, null);                                                      
 727                 updateItemArrays(item, itemId, stackTrace);                                              
 728             }                                                                                            
 729         };                                                                                               
 730         runOnWorkerThread(r);                                                                            
 731     }                                                                                                    
 732                                                                                                          
 733     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 734             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 735         final ContentResolver cr = context.getContentResolver();                                         
 736                                                                                                          
 737         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 738         Runnable r = new Runnable() {                                                                    
 739             public void run() {                                                                          
 740                 ArrayList<ContentProviderOperation> ops =                                                
 741                         new ArrayList<ContentProviderOperation>();                                       
 742                 int count = items.size();                                                                
 743                 for (int i = 0; i < count; i++) {                                                        
 744                     ItemInfo item = items.get(i);                                                        
 745                     final long itemId = item.id;                                                         
 746                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);             
 747                     ContentValues values = valuesList.get(i);                                            
 748                                                                                                          
 749                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 750                     updateItemArrays(item, itemId, stackTrace);                                          
 751                                                                                                          
 752                 }                                                                                        
 753                 try {                                                                                    
 754                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 755                 } catch (Exception e) {                                                                  
 756                     e.printStackTrace();                                                                 
 757                 }                                                                                        
 758             }                                                                                            
 759         };                                                                                               
 760         runOnWorkerThread(r);                                                                            
 761     }                                                                                                    
 762                                                                                                          
 763     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 764         // Lock on mBgLock *after* the db operation                                                      
 765         synchronized (sBgLock) {                                                                         
 766             checkItemInfoLocked(itemId, item, stackTrace);                                               
 767                                                                                                          
 768             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 769                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 770                 // Item is in a folder, make sure this folder exists                                     
 771                 if (!sBgFolders.containsKey(item.container)) {                                           
 772                     // An items container is being set to a that of an item which is not in              
 773                     // the list of Folders.                                                              
 774                     String msg = "item: " + item + " container being set to: " +                         
 775                             item.container + ", not in the list of folders";                             
 776                     Log.e(TAG, msg);                                                                     
 777                 }                                                                                        
 778             }                                                                                            
 779                                                                                                          
 780             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 781             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 782             // that are on the desktop, as appropriate                                                   
 783             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 784             if (modelItem != null &&                                                                     
 785                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 786                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 787                 switch (modelItem.itemType) {                                                            
 788                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 789                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 790                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 791                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 792                             sBgWorkspaceItems.add(modelItem);                                            
 793                         }                                                                                
 794                         break;                                                                           
 795                     default:                                                                             
 796                         break;                                                                           
 797                 }                                                                                        
 798             } else {                                                                                     
 799                 sBgWorkspaceItems.remove(modelItem);                                                     
 800             }                                                                                            
 801         }                                                                                                
 802     }                                                                                                    
 803                                                                                                          
 804     /**                                                                                                  
 805      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 806      */                                                                                                  
 807     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,           
 808             final long screenId, final int cellX, final int cellY) {                                     
 809         item.container = container;                                                                      
 810         item.cellX = cellX;                                                                              
 811         item.cellY = cellY;                                                                              
 812                                                                                                          
 813         // We store hotseat items in canonical form which is this orientation invariant position         
 814         // in the hotseat                                                                                
 815         if (context instanceof Launcher && screenId < 0 &&                                               
 816                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 817             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 818         } else {                                                                                         
 819             item.screenId = screenId;                                                                    
 820         }                                                                                                
 821                                                                                                          
 822         final ContentValues values = new ContentValues();                                                
 823         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 824         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 825         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 826         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 827         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 828                                                                                                          
 829         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 830     }                                                                                                    
 831                                                                                                          
 832     /**                                                                                                  
 833      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 834      * cellX, cellY have already been updated on the ItemInfos.                                          
 835      */                                                                                                  
 836     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 837             final long container, final int screen) {                                                    
 838                                                                                                          
 839         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 840         int count = items.size();                                                                        
 841                                                                                                          
 842         for (int i = 0; i < count; i++) {                                                                
 843             ItemInfo item = items.get(i);                                                                
 844             item.container = container;                                                                  
 845                                                                                                          
 846             // We store hotseat items in canonical form which is this orientation invariant position     
 847             // in the hotseat                                                                            
 848             if (context instanceof Launcher && screen < 0 &&                                             
 849                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 850                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 851                         item.cellY);                                                                     
 852             } else {                                                                                     
 853                 item.screenId = screen;                                                                  
 854             }                                                                                            
 855                                                                                                          
 856             final ContentValues values = new ContentValues();                                            
 857             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 858             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 859             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 860             values.put(LauncherSettings.Favorites.RANK, item.rank);                                      
 861             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 862                                                                                                          
 863             contentValues.add(values);                                                                   
 864         }                                                                                                
 865         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 866     }                                                                                                    
 867                                                                                                          
 868     /**                                                                                                  
 869      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 870      */                                                                                                  
 871     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 872             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 873         item.container = container;                                                                      
 874         item.cellX = cellX;                                                                              
 875         item.cellY = cellY;                                                                              
 876         item.spanX = spanX;                                                                              
 877         item.spanY = spanY;                                                                              
 878                                                                                                          
 879         // We store hotseat items in canonical form which is this orientation invariant position         
 880         // in the hotseat                                                                                
 881         if (context instanceof Launcher && screenId < 0 &&                                               
 882                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 883             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 884         } else {                                                                                         
 885             item.screenId = screenId;                                                                    
 886         }                                                                                                
 887                                                                                                          
 888         final ContentValues values = new ContentValues();                                                
 889         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 890         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 891         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 892         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 893         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 894         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 895         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 896                                                                                                          
 897         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 898     }                                                                                                    
 899                                                                                                          
 900     /**                                                                                                  
 901      * Update an item to the database in a specified container.                                          
 902      */                                                                                                  
 903     static void updateItemInDatabase(Context context, final ItemInfo item) {                             
 904         final ContentValues values = new ContentValues();                                                
 905         item.onAddToDatabase(context, values);                                                           
 906         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 907     }                                                                                                    
 908                                                                                                          
 909     /**                                                                                                  
 910      * Returns true if the shortcuts already exists in the database.                                     
 911      * we identify a shortcut by its title and intent.                                                   
 912      */                                                                                                  
 913     static boolean shortcutExists(Context context, String title, Intent intent,                          
 914             UserHandleCompat user) {                                                                     
 915         final ContentResolver cr = context.getContentResolver();                                         
 916         final Intent intentWithPkg, intentWithoutPkg;                                                    
 917                                                                                                          
 918         if (intent.getComponent() != null) {                                                             
 919             // If component is not null, an intent with null package will produce                        
 920             // the same result and should also be a match.                                               
 921             if (intent.getPackage() != null) {                                                           
 922                 intentWithPkg = intent;                                                                  
 923                 intentWithoutPkg = new Intent(intent).setPackage(null);                                  
 924             } else {                                                                                     
 925                 intentWithPkg = new Intent(intent).setPackage(                                           
 926                         intent.getComponent().getPackageName());                                         
 927                 intentWithoutPkg = intent;                                                               
 928             }                                                                                            
 929         } else {                                                                                         
 930             intentWithPkg = intent;                                                                      
 931             intentWithoutPkg = intent;                                                                   
 932         }                                                                                                
 933         String userSerial = Long.toString(UserManagerCompat.getInstance(context)                         
 934                 .getSerialNumberForUser(user));                                                          
 935         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 936             new String[] { "title", "intent", "profileId" },                                             
 937             "title=? and (intent=? or intent=?) and profileId=?",                                        
 938             new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },       
 939             null);                                                                                       
 940         try {                                                                                            
 941             return c.moveToFirst();                                                                      
 942         } finally {                                                                                      
 943             c.close();                                                                                   
 944         }                                                                                                
 945     }                                                                                                    
 946                                                                                                          
 947     /**                                                                                                  
 948      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 949      */                                                                                                  
 950     FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {            
 951         final ContentResolver cr = context.getContentResolver();                                         
 952         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 953                 "_id=? and (itemType=? or itemType=?)",                                                  
 954                 new String[] { String.valueOf(id),                                                       
 955                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 956                                                                                                          
 957         try {                                                                                            
 958             if (c.moveToFirst()) {                                                                       
 959                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 960                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 961                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 962                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 963                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 964                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 965                                                                                                          
 966                 FolderInfo folderInfo = null;                                                            
 967                 switch (c.getInt(itemTypeIndex)) {                                                       
 968                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 969                         folderInfo = findOrMakeFolder(folderList, id);                                   
 970                         break;                                                                           
 971                 }                                                                                        
 972                                                                                                          
 973                 folderInfo.title = c.getString(titleIndex);                                              
 974                 folderInfo.id = id;                                                                      
 975                 folderInfo.container = c.getInt(containerIndex);                                         
 976                 folderInfo.screenId = c.getInt(screenIndex);                                             
 977                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
 978                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
 979                                                                                                          
 980                 return folderInfo;                                                                       
 981             }                                                                                            
 982         } finally {                                                                                      
 983             c.close();                                                                                   
 984         }                                                                                                
 985                                                                                                          
 986         return null;                                                                                     
 987     }                                                                                                    
 988                                                                                                          
 989     /**                                                                                                  
 990      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
 991      * cellY fields of the item. Also assigns an ID to the item.                                         
 992      */                                                                                                  
 993     static void addItemToDatabase(Context context, final ItemInfo item, final long container,            
 994             final long screenId, final int cellX, final int cellY, final boolean notify) {               
 995         item.container = container;                                                                      
 996         item.cellX = cellX;                                                                              
 997         item.cellY = cellY;                                                                              
 998         // We store hotseat items in canonical form which is this orientation invariant position         
 999         // in the hotseat                                                                                
1000         if (context instanceof Launcher && screenId < 0 &&                                               
1001                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
1002             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1003         } else {                                                                                         
1004             item.screenId = screenId;                                                                    
1005         }                                                                                                
1006                                                                                                          
1007         final ContentValues values = new ContentValues();                                                
1008         final ContentResolver cr = context.getContentResolver();                                         
1009         item.onAddToDatabase(context, values);                                                           
1010                                                                                                          
1011         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1012         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1013                                                                                                          
1014         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
1015         Runnable r = new Runnable() {                                                                    
1016             public void run() {                                                                          
1017                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                              
1018                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                 
1019                                                                                                          
1020                 // Lock on mBgLock *after* the db operation                                              
1021                 synchronized (sBgLock) {                                                                 
1022                     checkItemInfoLocked(item.id, item, stackTrace);                                      
1023                     sBgItemsIdMap.put(item.id, item);                                                    
1024                     switch (item.itemType) {                                                             
1025                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1026                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1027                             // Fall through                                                              
1028                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1029                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1030                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1031                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1032                                 sBgWorkspaceItems.add(item);                                             
1033                             } else {                                                                     
1034                                 if (!sBgFolders.containsKey(item.container)) {                           
1035                                     // Adding an item to a folder that doesn't exist.                    
1036                                     String msg = "adding item: " + item + " to a folder that " +         
1037                                             " doesn't exist";                                            
1038                                     Log.e(TAG, msg);                                                     
1039                                 }                                                                        
1040                             }                                                                            
1041                             break;                                                                       
1042                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1043                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1044                             break;                                                                       
1045                     }                                                                                    
1046                 }                                                                                        
1047             }                                                                                            
1048         };                                                                                               
1049         runOnWorkerThread(r);                                                                            
1050     }                                                                                                    
1051                                                                                                          
1052     /**                                                                                                  
1053      * Creates a new unique child id, for a given cell span across all layouts.                          
1054      */                                                                                                  
1055     static int getCellLayoutChildId(                                                                     
1056             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1057         return (((int) container & 0xFF) << 24)                                                          
1058                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1059     }                                                                                                    
1060                                                                                                          
1061     private static ArrayList<ItemInfo> getItemsByPackageName(                                            
1062             final String pn, final UserHandleCompat user) {                                              
1063         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
1064             @Override                                                                                    
1065             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
1066                 return cn.getPackageName().equals(pn) && info.user.equals(user);                         
1067             }                                                                                            
1068         };                                                                                               
1069         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
1070     }                                                                                                    
1071                                                                                                          
1072     /**                                                                                                  
1073      * Removes all the items from the database corresponding to the specified package.                   
1074      */                                                                                                  
1075     static void deletePackageFromDatabase(Context context, final String pn,                              
1076             final UserHandleCompat user) {                                                               
1077         deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                               
1078     }                                                                                                    
1079                                                                                                          
1080     /**                                                                                                  
1081      * Removes the specified item from the database                                                      
1082      * @param context                                                                                    
1083      * @param item                                                                                       
1084      */                                                                                                  
1085     static void deleteItemFromDatabase(Context context, final ItemInfo item) {                           
1086         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1087         items.add(item);                                                                                 
1088         deleteItemsFromDatabase(context, items);                                                         
1089     }                                                                                                    
1090                                                                                                          
1091     /**                                                                                                  
1092      * Removes the specified items from the database                                                     
1093      * @param context                                                                                    
1094      * @param item                                                                                       
1095      */                                                                                                  
1096     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {    
1097         final ContentResolver cr = context.getContentResolver();                                         
1098                                                                                                          
1099         Runnable r = new Runnable() {                                                                    
1100             public void run() {                                                                          
1101                 for (ItemInfo item : items) {                                                            
1102                     final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);            
1103                     cr.delete(uri, null, null);                                                          
1104                                                                                                          
1105                     // Lock on mBgLock *after* the db operation                                          
1106                     synchronized (sBgLock) {                                                             
1107                         switch (item.itemType) {                                                         
1108                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
1109                                 sBgFolders.remove(item.id);                                              
1110                                 for (ItemInfo info: sBgItemsIdMap.values()) {                            
1111                                     if (info.container == item.id) {                                     
1112                                         // We are deleting a folder which still contains items that      
1113                                         // think they are contained by that folder.                      
1114                                         String msg = "deleting a folder (" + item + ") which still " +   
1115                                                 "contains items (" + info + ")";                         
1116                                         Log.e(TAG, msg);                                                 
1117                                     }                                                                    
1118                                 }                                                                        
1119                                 sBgWorkspaceItems.remove(item);                                          
1120                                 break;                                                                   
1121                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1122                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1123                                 sBgWorkspaceItems.remove(item);                                          
1124                                 break;                                                                   
1125                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
1126                                 sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                      
1127                                 break;                                                                   
1128                         }                                                                                
1129                         sBgItemsIdMap.remove(item.id);                                                   
1130                     }                                                                                    
1131                 }                                                                                        
1132             }                                                                                            
1133         };                                                                                               
1134         runOnWorkerThread(r);                                                                            
1135     }                                                                                                    
1136                                                                                                          
1137     /**                                                                                                  
1138      * Update the order of the workspace screens in the database. The array list contains                
1139      * a list of screen ids in the order that they should appear.                                        
1140      */                                                                                                  
1141     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1142         // Log to disk                                                                                   
1143         Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                       
1144         Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);        
1145                                                                                                          
1146         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1147         final ContentResolver cr = context.getContentResolver();                                         
1148         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1149                                                                                                          
1150         // Remove any negative screen ids -- these aren't persisted                                      
1151         Iterator<Long> iter = screensCopy.iterator();                                                    
1152         while (iter.hasNext()) {                                                                         
1153             long id = iter.next();                                                                       
1154             if (id < 0) {                                                                                
1155                 iter.remove();                                                                           
1156             }                                                                                            
1157         }                                                                                                
1158                                                                                                          
1159         Runnable r = new Runnable() {                                                                    
1160             @Override                                                                                    
1161             public void run() {                                                                          
1162                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
1163                 // Clear the table                                                                       
1164                 ops.add(ContentProviderOperation.newDelete(uri).build());                                
1165                 int count = screensCopy.size();                                                          
1166                 for (int i = 0; i < count; i++) {                                                        
1167                     ContentValues v = new ContentValues();                                               
1168                     long screenId = screensCopy.get(i);                                                  
1169                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1170                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1171                     ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());              
1172                 }                                                                                        
1173                                                                                                          
1174                 try {                                                                                    
1175                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
1176                 } catch (Exception ex) {                                                                 
1177                     throw new RuntimeException(ex);                                                      
1178                 }                                                                                        
1179                                                                                                          
1180                 synchronized (sBgLock) {                                                                 
1181                     sBgWorkspaceScreens.clear();                                                         
1182                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1183                 }                                                                                        
1184             }                                                                                            
1185         };                                                                                               
1186         runOnWorkerThread(r);                                                                            
1187     }                                                                                                    
1188                                                                                                          
1189     /**                                                                                                  
1190      * Remove the contents of the specified folder from the database                                     
1191      */                                                                                                  
1192     static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {               
1193         final ContentResolver cr = context.getContentResolver();                                         
1194                                                                                                          
1195         Runnable r = new Runnable() {                                                                    
1196             public void run() {                                                                          
1197                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);         
1198                 // Lock on mBgLock *after* the db operation                                              
1199                 synchronized (sBgLock) {                                                                 
1200                     sBgItemsIdMap.remove(info.id);                                                       
1201                     sBgFolders.remove(info.id);                                                          
1202                     sBgWorkspaceItems.remove(info);                                                      
1203                 }                                                                                        
1204                                                                                                          
1205                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                        
1206                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1207                 // Lock on mBgLock *after* the db operation                                              
1208                 synchronized (sBgLock) {                                                                 
1209                     for (ItemInfo childInfo : info.contents) {                                           
1210                         sBgItemsIdMap.remove(childInfo.id);                                              
1211                     }                                                                                    
1212                 }                                                                                        
1213             }                                                                                            
1214         };                                                                                               
1215         runOnWorkerThread(r);                                                                            
1216     }                                                                                                    
1217                                                                                                          
1218     /**                                                                                                  
1219      * Set this as the current Launcher activity object for the loader.                                  
1220      */                                                                                                  
1221     public void initialize(Callbacks callbacks) {                                                        
1222         synchronized (mLock) {                                                                           
1223             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1224         }                                                                                                
1225     }                                                                                                    
1226                                                                                                          
1227     @Override                                                                                            
1228     public void onPackageChanged(String packageName, UserHandleCompat user) {                            
1229         int op = PackageUpdatedTask.OP_UPDATE;                                                           
1230         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1231                 user));                                                                                  
1232     }                                                                                                    
1233                                                                                                          
1234     @Override                                                                                            
1235     public void onPackageRemoved(String packageName, UserHandleCompat user) {                            
1236         int op = PackageUpdatedTask.OP_REMOVE;                                                           
1237         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1238                 user));                                                                                  
1239     }                                                                                                    
1240                                                                                                          
1241     @Override                                                                                            
1242     public void onPackageAdded(String packageName, UserHandleCompat user) {                              
1243         int op = PackageUpdatedTask.OP_ADD;                                                              
1244         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1245                 user));                                                                                  
1246     }                                                                                                    
1247                                                                                                          
1248     @Override                                                                                            
1249     public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                        
1250             boolean replacing) {                                                                         
1251         if (!replacing) {                                                                                
1252             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,        
1253                     user));                                                                              
1254             if (mAppsCanBeOnRemoveableStorage) {                                                         
1255                 // Only rebind if we support removable storage. It catches the                           
1256                 // case where                                                                            
1257                 // apps on the external sd card need to be reloaded                                      
1258                 startLoaderFromBackground();                                                             
1259             }                                                                                            
1260         } else {                                                                                         
1261             // If we are replacing then just update the packages in the list                             
1262             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                   
1263                     packageNames, user));                                                                
1264         }                                                                                                
1265     }                                                                                                    
1266                                                                                                          
1267     @Override                                                                                            
1268     public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                      
1269             boolean replacing) {                                                                         
1270         if (!replacing) {                                                                                
1271             enqueuePackageUpdated(new PackageUpdatedTask(                                                
1272                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                     
1273                     user));                                                                              
1274         }                                                                                                
1275     }                                                                                                    
1276                                                                                                          
1277     /**                                                                                                  
1278      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1279      * ACTION_PACKAGE_CHANGED.                                                                           
1280      */                                                                                                  
1281     @Override                                                                                            
1282     public void onReceive(Context context, Intent intent) {                                              
1283         if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                    
1284                                                                                                          
1285         final String action = intent.getAction();                                                        
1286         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                               
1287             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1288             forceReload();                                                                               
1289         } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                 
1290              // Check if configuration change was an mcc/mnc change which would affect app resources     
1291              // and we would need to clear out the labels in all apps/workspace. Same handling as        
1292              // above for ACTION_LOCALE_CHANGED                                                          
1293              Configuration currentConfig = context.getResources().getConfiguration();                    
1294              if (mPreviousConfigMcc != currentConfig.mcc) {                                              
1295                    Log.d(TAG, "Reload apps on config change. curr_mcc:"                                  
1296                        + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                          
1297                    forceReload();                                                                        
1298              }                                                                                           
1299              // Update previousConfig                                                                    
1300              mPreviousConfigMcc = currentConfig.mcc;                                                     
1301         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1302                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1303             Callbacks callbacks = getCallback();                                                         
1304             if (callbacks != null) {                                                                     
1305                 callbacks.bindSearchablesChanged();                                                      
1306             }                                                                                            
1307         }                                                                                                
1308     }                                                                                                    
1309                                                                                                          
1310     void forceReload() {                                                                                 
1311         resetLoadedState(true, true);                                                                    
1312                                                                                                          
1313         // Do this here because if the launcher activity is running it will be restarted.                
1314         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1315         // to reload.                                                                                    
1316         startLoaderFromBackground();                                                                     
1317     }                                                                                                    
1318                                                                                                          
1319     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1320         synchronized (mLock) {                                                                           
1321             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1322             // mWorkspaceLoaded to true later                                                            
1323             stopLoaderLocked();                                                                          
1324             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1325             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1326         }                                                                                                
1327     }                                                                                                    
1328                                                                                                          
1329     /**                                                                                                  
1330      * When the launcher is in the background, it's possible for it to miss paired                       
1331      * configuration changes.  So whenever we trigger the loader from the background                     
1332      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1333      * of doing it now.                                                                                  
1334      */                                                                                                  
1335     public void startLoaderFromBackground() {                                                            
1336         boolean runLoader = false;                                                                       
1337         Callbacks callbacks = getCallback();                                                             
1338         if (callbacks != null) {                                                                         
1339             // Only actually run the loader if they're not paused.                                       
1340             if (!callbacks.setLoadOnResume()) {                                                          
1341                 runLoader = true;                                                                        
1342             }                                                                                            
1343         }                                                                                                
1344         if (runLoader) {                                                                                 
1345             startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                          
1346         }                                                                                                
1347     }                                                                                                    
1348                                                                                                          
1349     // If there is already a loader task running, tell it to stop.                                       
1350     // returns true if isLaunching() was true on the old task                                            
1351     private boolean stopLoaderLocked() {                                                                 
1352         boolean isLaunching = false;                                                                     
1353         LoaderTask oldTask = mLoaderTask;                                                                
1354         if (oldTask != null) {                                                                           
1355             if (oldTask.isLaunching()) {                                                                 
1356                 isLaunching = true;                                                                      
1357             }                                                                                            
1358             oldTask.stopLocked();                                                                        
1359         }                                                                                                
1360         return isLaunching;                                                                              
1361     }                                                                                                    
1362                                                                                                          
1363     public boolean isCurrentCallbacks(Callbacks callbacks) {                                             
1364         return (mCallbacks != null && mCallbacks.get() == callbacks);                                    
1365     }                                                                                                    
1366                                                                                                          
1367     public void startLoader(boolean isLaunching, int synchronousBindPage) {                              
1368         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                 
1369     }                                                                                                    
1370                                                                                                          
1371     public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {               
1372         synchronized (mLock) {                                                                           
1373             if (DEBUG_LOADERS) {                                                                         
1374                 Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                    
1375             }                                                                                            
1376                                                                                                          
1377             // Clear any deferred bind-runnables from the synchronized load process                      
1378             // We must do this before any loading/binding is scheduled below.                            
1379             synchronized (mDeferredBindRunnables) {                                                      
1380                 mDeferredBindRunnables.clear();                                                          
1381             }                                                                                            
1382                                                                                                          
1383             // Don't bother to start the thread if we know it's not going to do anything                 
1384             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1385                 // If there is already one running, tell it to stop.                                     
1386                 // also, don't downgrade isLaunching if we're already running                            
1387                 isLaunching = isLaunching || stopLoaderLocked();                                         
1388                 mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                 
1389                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1390                         && mAllAppsLoaded && mWorkspaceLoaded) {                                         
1391                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1392                 } else {                                                                                 
1393                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1394                     sWorker.post(mLoaderTask);                                                           
1395                 }                                                                                        
1396             }                                                                                            
1397         }                                                                                                
1398     }                                                                                                    
1399                                                                                                          
1400     void bindRemainingSynchronousPages() {                                                               
1401         // Post the remaining side pages to be loaded                                                    
1402         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1403             Runnable[] deferredBindRunnables = null;                                                     
1404             synchronized (mDeferredBindRunnables) {                                                      
1405                 deferredBindRunnables = mDeferredBindRunnables.toArray(                                  
1406                         new Runnable[mDeferredBindRunnables.size()]);                                    
1407                 mDeferredBindRunnables.clear();                                                          
1408             }                                                                                            
1409             for (final Runnable r : deferredBindRunnables) {                                             
1410                 mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                          
1411             }                                                                                            
1412         }                                                                                                
1413     }                                                                                                    
1414                                                                                                          
1415     public void stopLoader() {                                                                           
1416         synchronized (mLock) {                                                                           
1417             if (mLoaderTask != null) {                                                                   
1418                 mLoaderTask.stopLocked();                                                                
1419             }                                                                                            
1420         }                                                                                                
1421     }                                                                                                    
1422                                                                                                          
1423     /**                                                                                                  
1424      * Loads the workspace screen ids in an ordered list.                                                
1425      */                                                                                                  
1426     private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                             
1427         final ContentResolver contentResolver = context.getContentResolver();                            
1428         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1429                                                                                                          
1430         // Get screens ordered by rank.                                                                  
1431         final Cursor sc = contentResolver.query(screensUri, null, null, null,                            
1432                 LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                          
1433         ArrayList<Long> screenIds = new ArrayList<Long>();                                               
1434         try {                                                                                            
1435             final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);         
1436             while (sc.moveToNext()) {                                                                    
1437                 try {                                                                                    
1438                     screenIds.add(sc.getLong(idIndex));                                                  
1439                 } catch (Exception e) {                                                                  
1440                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                         
1441                             + " - invalid screens: " + e, true);                                         
1442                 }                                                                                        
1443             }                                                                                            
1444         } finally {                                                                                      
1445             sc.close();                                                                                  
1446         }                                                                                                
1447         return screenIds;                                                                                
1448     }                                                                                                    
1449                                                                                                          
1450     public boolean isAllAppsLoaded() {                                                                   
1451         return mAllAppsLoaded;                                                                           
1452     }                                                                                                    
1453                                                                                                          
1454     boolean isLoadingWorkspace() {                                                                       
1455         synchronized (mLock) {                                                                           
1456             if (mLoaderTask != null) {                                                                   
1457                 return mLoaderTask.isLoadingWorkspace();                                                 
1458             }                                                                                            
1459         }                                                                                                
1460         return false;                                                                                    
1461     }                                                                                                    
1462                                                                                                          
1463     /**                                                                                                  
1464      * Runnable for the thread that loads the contents of the launcher:                                  
1465      *   - workspace icons                                                                               
1466      *   - widgets                                                                                       
1467      *   - all apps icons                                                                                
1468      */                                                                                                  
1469     private class LoaderTask implements Runnable {                                                       
1470         private Context mContext;                                                                        
1471         private boolean mIsLaunching;                                                                    
1472         private boolean mIsLoadingAndBindingWorkspace;                                                   
1473         private boolean mStopped;                                                                        
1474         private boolean mLoadAndBindStepFinished;                                                        
1475         private int mFlags;                                                                              
1476                                                                                                          
1477         LoaderTask(Context context, boolean isLaunching, int flags) {                                    
1478             mContext = context;                                                                          
1479             mIsLaunching = isLaunching;                                                                  
1480             mFlags = flags;                                                                              
1481         }                                                                                                
1482                                                                                                          
1483         boolean isLaunching() {                                                                          
1484             return mIsLaunching;                                                                         
1485         }                                                                                                
1486                                                                                                          
1487         boolean isLoadingWorkspace() {                                                                   
1488             return mIsLoadingAndBindingWorkspace;                                                        
1489         }                                                                                                
1490                                                                                                          
1491         private void loadAndBindWorkspace() {                                                            
1492             mIsLoadingAndBindingWorkspace = true;                                                        
1493                                                                                                          
1494             // Load the workspace                                                                        
1495             if (DEBUG_LOADERS) {                                                                         
1496                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1497             }                                                                                            
1498                                                                                                          
1499             if (!mWorkspaceLoaded) {                                                                     
1500                 loadWorkspace();                                                                         
1501                 synchronized (LoaderTask.this) {                                                         
1502                     if (mStopped) {                                                                      
1503                         return;                                                                          
1504                     }                                                                                    
1505                     mWorkspaceLoaded = true;                                                             
1506                 }                                                                                        
1507             }                                                                                            
1508                                                                                                          
1509             // Bind the workspace                                                                        
1510             bindWorkspace(-1);                                                                           
1511         }                                                                                                
1512                                                                                                          
1513         private void waitForIdle() {                                                                     
1514             // Wait until the either we're stopped or the other threads are done.                        
1515             // This way we don't start loading all apps until the workspace has settled                  
1516             // down.                                                                                     
1517             synchronized (LoaderTask.this) {                                                             
1518                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1519                                                                                                          
1520                 mHandler.postIdle(new Runnable() {                                                       
1521                         public void run() {                                                              
1522                             synchronized (LoaderTask.this) {                                             
1523                                 mLoadAndBindStepFinished = true;                                         
1524                                 if (DEBUG_LOADERS) {                                                     
1525                                     Log.d(TAG, "done with previous binding step");                       
1526                                 }                                                                        
1527                                 LoaderTask.this.notify();                                                
1528                             }                                                                            
1529                         }                                                                                
1530                     });                                                                                  
1531                                                                                                          
1532                 while (!mStopped && !mLoadAndBindStepFinished) {                                         
1533                     try {                                                                                
1534                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1535                         // wait no longer than 1sec at a time                                            
1536                         this.wait(1000);                                                                 
1537                     } catch (InterruptedException ex) {                                                  
1538                         // Ignore                                                                        
1539                     }                                                                                    
1540                 }                                                                                        
1541                 if (DEBUG_LOADERS) {                                                                     
1542                     Log.d(TAG, "waited "                                                                 
1543                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1544                             + "ms for previous step to finish binding");                                 
1545                 }                                                                                        
1546             }                                                                                            
1547         }                                                                                                
1548                                                                                                          
1549         void runBindSynchronousPage(int synchronousBindPage) {                                           
1550             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1551                 // Ensure that we have a valid page index to load synchronously                          
1552                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1553                         "valid page index");                                                             
1554             }                                                                                            
1555             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1556                 // Ensure that we don't try and bind a specified page when the pages have not been       
1557                 // loaded already (we should load everything asynchronously in that case)                
1558                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1559             }                                                                                            
1560             synchronized (mLock) {                                                                       
1561                 if (mIsLoaderTaskRunning) {                                                              
1562                     // Ensure that we are never running the background loading at this point since       
1563                     // we also touch the background collections                                          
1564                     throw new RuntimeException("Error! Background loading is already running");          
1565                 }                                                                                        
1566             }                                                                                            
1567                                                                                                          
1568             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1569             //      data structures, we can't allow any other thread to touch that data, but because     
1570             //      this call is synchronous, we can get away with not locking).                         
1571                                                                                                          
1572             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1573             // operations from the previous activity.  We need to ensure that all queued operations      
1574             // are executed before any synchronous binding work is done.                                 
1575             mHandler.flush();                                                                            
1576                                                                                                          
1577             // Divide the set of loaded items into those that we are binding synchronously, and          
1578             // everything else that is to be bound normally (asynchronously).                            
1579             bindWorkspace(synchronousBindPage);                                                          
1580             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1581             //      arise from that.                                                                     
1582             onlyBindAllApps();                                                                           
1583         }                                                                                                
1584                                                                                                          
1585         public void run() {                                                                              
1586             synchronized (mLock) {                                                                       
1587                 mIsLoaderTaskRunning = true;                                                             
1588             }                                                                                            
1589             // Optimize for end-user experience: if the Launcher is up and // running with the           
1590             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1591             // workspace first (default).                                                                
1592             keep_running: {                                                                              
1593                 // Elevate priority when Home launches for the first time to avoid                       
1594                 // starving at boot time. Staring at a blank home is not cool.                           
1595                 synchronized (mLock) {                                                                   
1596                     if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                        
1597                             (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                  
1598                     android.os.Process.setThreadPriority(mIsLaunching                                    
1599                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);     
1600                 }                                                                                        
1601                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1602                 loadAndBindWorkspace();                                                                  
1603                                                                                                          
1604                 if (mStopped) {                                                                          
1605                     break keep_running;                                                                  
1606                 }                                                                                        
1607                                                                                                          
1608                 // Whew! Hard work done.  Slow us down, and wait until the UI thread has                 
1609                 // settled down.                                                                         
1610                 synchronized (mLock) {                                                                   
1611                     if (mIsLaunching) {                                                                  
1612                         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");          
1613                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        
1614                     }                                                                                    
1615                 }                                                                                        
1616                 waitForIdle();                                                                           
1617                                                                                                          
1618                 // second step                                                                           
1619                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1620                 loadAndBindAllApps();                                                                    
1621                                                                                                          
1622                 // Restore the default thread priority after we are done loading items                   
1623                 synchronized (mLock) {                                                                   
1624                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1625                 }                                                                                        
1626             }                                                                                            
1627                                                                                                          
1628 <<<<<<< MINE                                                                                             
1629             if (LauncherAppState.isDisableAllApps()) {                                                   
1630                 // Ensure that all the applications that are in the system are                           
1631                 // represented on the home screen.                                                       
1632                 verifyApplications();                                                                    
1633 ||||||| BASE                                                                                             
1634             // Update the saved icons if necessary                                                       
1635             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1636             synchronized (sBgLock) {                                                                     
1637                 for (Object key : sBgDbIconCache.keySet()) {                                             
1638                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1639                 }                                                                                        
1640                 sBgDbIconCache.clear();                                                                  
1641 =======                                                                                                  
1642             // Update the saved icons if necessary                                                       
1643             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1644             synchronized (sBgLock) {                                                                     
1645                 for (Object key : sBgDbIconCache.keySet()) {                                             
1646                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1647                 }                                                                                        
1648                 sBgDbIconCache.clear();                                                                  
1649 >>>>>>> YOURS                                                                                            
1650             }                                                                                            
1651                                                                                                          
1652             // Clear out this reference, otherwise we end up holding it until all of the                 
1653             // callback runnables are done.                                                              
1654             mContext = null;                                                                             
1655                                                                                                          
1656             synchronized (mLock) {                                                                       
1657                 // If we are still the last one to be scheduled, remove ourselves.                       
1658                 if (mLoaderTask == this) {                                                               
1659                     mLoaderTask = null;                                                                  
1660                 }                                                                                        
1661                 mIsLoaderTaskRunning = false;                                                            
1662             }                                                                                            
1663         }                                                                                                
1664                                                                                                          
1665         public void stopLocked() {                                                                       
1666             synchronized (LoaderTask.this) {                                                             
1667                 mStopped = true;                                                                         
1668                 this.notify();                                                                           
1669             }                                                                                            
1670         }                                                                                                
1671                                                                                                          
1672         /**                                                                                              
1673          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1674          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1675          * object that was around when the deferred message was scheduled, and if there's                
1676          * a new Callbacks object around then also return null.  This will save us from                  
1677          * calling onto it with data that will be ignored.                                               
1678          */                                                                                              
1679         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1680             synchronized (mLock) {                                                                       
1681                 if (mStopped) {                                                                          
1682                     return null;                                                                         
1683                 }                                                                                        
1684                                                                                                          
1685                 if (mCallbacks == null) {                                                                
1686                     return null;                                                                         
1687                 }                                                                                        
1688                                                                                                          
1689                 final Callbacks callbacks = mCallbacks.get();                                            
1690                 if (callbacks != oldCallbacks) {                                                         
1691                     return null;                                                                         
1692                 }                                                                                        
1693                 if (callbacks == null) {                                                                 
1694                     Log.w(TAG, "no mCallbacks");                                                         
1695                     return null;                                                                         
1696                 }                                                                                        
1697                                                                                                          
1698                 return callbacks;                                                                        
1699             }                                                                                            
1700         }                                                                                                
1701                                                                                                          
1702         // check & update map of what's occupied; used to discard overlapping/invalid items              
1703         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {        
1704             LauncherAppState app = LauncherAppState.getInstance();                                       
1705             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1706             final int countX = (int) grid.numColumns;                                                    
1707             final int countY = (int) grid.numRows;                                                       
1708                                                                                                          
1709             long containerIndex = item.screenId;                                                         
1710             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1711                 // Return early if we detect that an item is under the hotseat button                    
1712                 if (mCallbacks == null ||                                                                
1713                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1714                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1715                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1716                             + item.cellY + ") occupied by all apps");                                    
1717                     return false;                                                                        
1718                 }                                                                                        
1719                                                                                                          
1720                 final ItemInfo[][] hotseatItems =                                                        
1721                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1722                                                                                                          
1723                 if (item.screenId >= grid.numHotseatIcons) {                                             
1724                     Log.e(TAG, "Error loading shortcut " + item                                          
1725                             + " into hotseat position " + item.screenId                                  
1726                             + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)            
1727                             + ")");                                                                      
1728                     return false;                                                                        
1729                 }                                                                                        
1730                                                                                                          
1731                 if (hotseatItems != null) {                                                              
1732                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1733                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1734                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1735                                 + item.cellY + ") occupied by "                                          
1736                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1737                                 [(int) item.screenId][0]);                                               
1738                             return false;                                                                
1739                     } else {                                                                             
1740                         hotseatItems[(int) item.screenId][0] = item;                                     
1741                         return true;                                                                     
1742                     }                                                                                    
1743                 } else {                                                                                 
1744                     final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];              
1745                     items[(int) item.screenId][0] = item;                                                
1746                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1747                     return true;                                                                         
1748                 }                                                                                        
1749             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1750                 // Skip further checking if it is not the hotseat or workspace container                 
1751                 return true;                                                                             
1752             }                                                                                            
1753                                                                                                          
1754             if (!occupied.containsKey(item.screenId)) {                                                  
1755                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1756                 occupied.put(item.screenId, items);                                                      
1757             }                                                                                            
1758                                                                                                          
1759             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1760             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1761                     item.cellX < 0 || item.cellY < 0 ||                                                  
1762                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1763                 Log.e(TAG, "Error loading shortcut " + item                                              
1764                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1765                         + item.cellX + "," + item.cellY                                                  
1766                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1767                 return false;                                                                            
1768             }                                                                                            
1769                                                                                                          
1770             // Check if any workspace icons overlap with each other                                      
1771             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1772                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1773                     if (screens[x][y] != null) {                                                         
1774                         Log.e(TAG, "Error loading shortcut " + item                                      
1775                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1776                             + x + "," + y                                                                
1777                             + ") occupied by "                                                           
1778                             + screens[x][y]);                                                            
1779                         return false;                                                                    
1780                     }                                                                                    
1781                 }                                                                                        
1782             }                                                                                            
1783             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1784                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1785                     screens[x][y] = item;                                                                
1786                 }                                                                                        
1787             }                                                                                            
1788                                                                                                          
1789             return true;                                                                                 
1790         }                                                                                                
1791                                                                                                          
1792         /** Clears all the sBg data structures */                                                        
1793         private void clearSBgDataStructures() {                                                          
1794             synchronized (sBgLock) {                                                                     
1795                 sBgWorkspaceItems.clear();                                                               
1796                 sBgAppWidgets.clear();                                                                   
1797                 sBgFolders.clear();                                                                      
1798                 sBgItemsIdMap.clear();                                                                   
1799                 sBgWorkspaceScreens.clear();                                                             
1800             }                                                                                            
1801         }                                                                                                
1802                                                                                                          
1803         private void loadWorkspace() {                                                                   
1804             // Log to disk                                                                               
1805             Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                
1806                                                                                                          
1807             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                               
1808                                                                                                          
1809             final Context context = mContext;                                                            
1810             final ContentResolver contentResolver = context.getContentResolver();                        
1811             final PackageManager manager = context.getPackageManager();                                  
1812             final boolean isSafeMode = manager.isSafeMode();                                             
1813             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);             
1814             final boolean isSdCardReady = context.registerReceiver(null,                                 
1815                     new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                             
1816                                                                                                          
1817             LauncherAppState app = LauncherAppState.getInstance();                                       
1818             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1819             int countX = (int) grid.numColumns;                                                          
1820             int countY = (int) grid.numRows;                                                             
1821                                                                                                          
1822             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1823                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1824                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1825             }                                                                                            
1826                                                                                                          
1827             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1828                 // append the user's Launcher2 shortcuts                                                 
1829                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1830                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1831             } else {                                                                                     
1832                 // Make sure the default workspace is loaded                                             
1833                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1834                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                
1835             }                                                                                            
1836                                                                                                          
1837             synchronized (sBgLock) {                                                                     
1838                 clearSBgDataStructures();                                                                
1839                 final HashSet<String> installingPkgs = PackageInstallerCompat                            
1840                         .getInstance(mContext).updateAndGetActiveSessionCache();                         
1841                                                                                                          
1842                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1843                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1844                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;           
1845                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                       
1846                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1847                                                                                                          
1848                 // +1 for the hotseat (it can be larger than the workspace)                              
1849                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1850                 // before any earlier duplicates)                                                        
1851                 final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();          
1852                                                                                                          
1853                 try {                                                                                    
1854                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1855                     final int intentIndex = c.getColumnIndexOrThrow                                      
1856                             (LauncherSettings.Favorites.INTENT);                                         
1857                     final int titleIndex = c.getColumnIndexOrThrow                                       
1858                             (LauncherSettings.Favorites.TITLE);                                          
1859                     final int iconTypeIndex = c.getColumnIndexOrThrow(                                   
1860                             LauncherSettings.Favorites.ICON_TYPE);                                       
1861                     final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);      
1862                     final int iconPackageIndex = c.getColumnIndexOrThrow(                                
1863                             LauncherSettings.Favorites.ICON_PACKAGE);                                    
1864                     final int iconResourceIndex = c.getColumnIndexOrThrow(                               
1865                             LauncherSettings.Favorites.ICON_RESOURCE);                                   
1866                     final int containerIndex = c.getColumnIndexOrThrow(                                  
1867                             LauncherSettings.Favorites.CONTAINER);                                       
1868                     final int itemTypeIndex = c.getColumnIndexOrThrow(                                   
1869                             LauncherSettings.Favorites.ITEM_TYPE);                                       
1870                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                
1871                             LauncherSettings.Favorites.APPWIDGET_ID);                                    
1872                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                          
1873                             LauncherSettings.Favorites.APPWIDGET_PROVIDER);                              
1874                     final int screenIndex = c.getColumnIndexOrThrow(                                     
1875                             LauncherSettings.Favorites.SCREEN);                                          
1876                     final int cellXIndex = c.getColumnIndexOrThrow                                       
1877                             (LauncherSettings.Favorites.CELLX);                                          
1878                     final int cellYIndex = c.getColumnIndexOrThrow                                       
1879                             (LauncherSettings.Favorites.CELLY);                                          
1880                     final int spanXIndex = c.getColumnIndexOrThrow                                       
1881                             (LauncherSettings.Favorites.SPANX);                                          
1882                     final int spanYIndex = c.getColumnIndexOrThrow(                                      
1883                             LauncherSettings.Favorites.SPANY);                                           
1884                     final int rankIndex = c.getColumnIndexOrThrow(                                       
1885                             LauncherSettings.Favorites.RANK);                                            
1886                     final int restoredIndex = c.getColumnIndexOrThrow(                                   
1887                             LauncherSettings.Favorites.RESTORED);                                        
1888                     final int profileIdIndex = c.getColumnIndexOrThrow(                                  
1889                             LauncherSettings.Favorites.PROFILE_ID);                                      
1890                     //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);      
1891                     //final int displayModeIndex = c.getColumnIndexOrThrow(                              
1892                     //        LauncherSettings.Favorites.DISPLAY_MODE);                                  
1893                                                                                                          
1894                     ShortcutInfo info;                                                                   
1895                     String intentDescription;                                                            
1896                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1897                     int container;                                                                       
1898                     long id;                                                                             
1899                     Intent intent;                                                                       
1900                     UserHandleCompat user;                                                               
1901                                                                                                          
1902                     while (!mStopped && c.moveToNext()) {                                                
1903                         try {                                                                            
1904                             int itemType = c.getInt(itemTypeIndex);                                      
1905                             boolean restored = 0 != c.getInt(restoredIndex);                             
1906                             boolean allowMissingTarget = false;                                          
1907                                                                                                          
1908                             switch (itemType) {                                                          
1909                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1910                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1911                                 id = c.getLong(idIndex);                                                 
1912                                 intentDescription = c.getString(intentIndex);                            
1913                                 long serialNumber = c.getInt(profileIdIndex);                            
1914                                 user = mUserManager.getUserForSerialNumber(serialNumber);                
1915                                 int promiseType = c.getInt(restoredIndex);                               
1916                                 int disabledState = 0;                                                   
1917                                 boolean itemReplaced = false;                                            
1918                                 if (user == null) {                                                      
1919                                     // User has been deleted remove the item.                            
1920                                     itemsToRemove.add(id);                                               
1921                                     continue;                                                            
1922                                 }                                                                        
1923                                 try {                                                                    
1924                                     intent = Intent.parseUri(intentDescription, 0);                      
1925                                     ComponentName cn = intent.getComponent();                            
1926                                     if (cn != null && cn.getPackageName() != null) {                     
1927                                         boolean validPkg = launcherApps.isPackageEnabledForProfile(      
1928                                                 cn.getPackageName(), user);                              
1929                                         boolean validComponent = validPkg &&                             
1930                                                 launcherApps.isActivityEnabledForProfile(cn, user);      
1931                                                                                                          
1932                                         if (validComponent) {                                            
1933                                             if (restored) {                                              
1934                                                 // no special handling necessary for this item           
1935                                                 restoredRows.add(id);                                    
1936                                                 restored = false;                                        
1937                                             }                                                            
1938                                         } else if (validPkg) {                                           
1939                                             intent = null;                                               
1940                                             if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
1941                                                 // We allow auto install apps to have their intent       
1942                                                 // updated after an install.                             
1943                                                 intent = manager.getLaunchIntentForPackage(              
1944                                                         cn.getPackageName());                            
1945                                                 if (intent != null) {                                    
1946                                                     ContentValues values = new ContentValues();          
1947                                                     values.put(LauncherSettings.Favorites.INTENT,        
1948                                                             intent.toUri(0));                            
1949                                                     updateItem(id, values);                              
1950                                                 }                                                        
1951                                             }                                                            
1952                                                                                                          
1953                                             if (intent == null) {                                        
1954                                                 // The app is installed but the component is no          
1955                                                 // longer available.                                     
1956                                                 Launcher.addDumpLog(TAG,                                 
1957                                                         "Invalid component removed: " + cn, true);       
1958                                                 itemsToRemove.add(id);                                   
1959                                                 continue;                                                
1960                                             } else {                                                     
1961                                                 // no special handling necessary for this item           
1962                                                 restoredRows.add(id);                                    
1963                                                 restored = false;                                        
1964                                             }                                                            
1965                                         } else if (restored) {                                           
1966                                             // Package is not yet available but might be                 
1967                                             // installed later.                                          
1968                                             Launcher.addDumpLog(TAG,                                     
1969                                                     "package not yet restored: " + cn, true);            
1970                                                                                                          
1971                                             if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {
1972                                                 // Restore has started once.                             
1973                                             } else if (installingPkgs.contains(cn.getPackageName())) {   
1974                                                 // App restore has started. Update the flag              
1975                                                 promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;        
1976                                                 ContentValues values = new ContentValues();              
1977                                                 values.put(LauncherSettings.Favorites.RESTORED,          
1978                                                         promiseType);                                    
1979                                                 updateItem(id, values);                                  
1980                                             } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE🔵
1981                                                 // This is a common app. Try to replace this.            
1982                                                 int appType = CommonAppTypeParser.decodeItemTypeFromFlag(🔵
1983                                                 CommonAppTypeParser parser = new CommonAppTypeParser(id, 🔵
1984                                                 if (parser.findDefaultApp()) {                           
1985                                                     // Default app found. Replace it.                    
1986                                                     intent = parser.parsedIntent;                        
1987                                                     cn = intent.getComponent();                          
1988                                                     ContentValues values = parser.parsedValues;          
1989                                                     values.put(LauncherSettings.Favorites.RESTORED, 0);  
1990                                                     updateItem(id, values);                              
1991                                                     restored = false;                                    
1992                                                     itemReplaced = true;                                 
1993                                                                                                          
1994                                                 } else if (REMOVE_UNRESTORED_ICONS) {                    
1995                                                     Launcher.addDumpLog(TAG,                             
1996                                                             "Unrestored package removed: " + cn, true);  
1997                                                     itemsToRemove.add(id);                               
1998                                                     continue;                                            
1999                                                 }                                                        
2000                                             } else if (REMOVE_UNRESTORED_ICONS) {                        
2001                                                 Launcher.addDumpLog(TAG,                                 
2002                                                         "Unrestored package removed: " + cn, true);      
2003                                                 itemsToRemove.add(id);                                   
2004                                                 continue;                                                
2005                                             }                                                            
2006                                         } else if (launcherApps.isAppEnabled(                            
2007                                                 manager, cn.getPackageName(),                            
2008                                                 PackageManager.GET_UNINSTALLED_PACKAGES)) {              
2009                                             // Package is present but not available.                     
2010                                             allowMissingTarget = true;                                   
2011                                             disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;    
2012                                         } else if (!isSdCardReady) {                                     
2013                                             // SdCard is not ready yet. Package might get available,     
2014                                             // once it is ready.                                         
2015                                             Launcher.addDumpLog(TAG, "Invalid package: " + cn            
2016                                                     + " (check again later)", true);                     
2017                                             HashSet<String> pkgs = sPendingPackages.get(user);           
2018                                             if (pkgs == null) {                                          
2019                                                 pkgs = new HashSet<String>();                            
2020                                                 sPendingPackages.put(user, pkgs);                        
2021                                             }                                                            
2022                                             pkgs.add(cn.getPackageName());                               
2023                                             allowMissingTarget = true;                                   
2024                                             // Add the icon on the workspace anyway.                     
2025                                                                                                          
2026                                         } else {                                                         
2027                                             // Do not wait for external media load anymore.              
2028                                             // Log the invalid package, and remove it                    
2029                                             Launcher.addDumpLog(TAG,                                     
2030                                                     "Invalid package removed: " + cn, true);             
2031                                             itemsToRemove.add(id);                                       
2032                                             continue;                                                    
2033                                         }                                                                
2034                                     } else if (cn == null) {                                             
2035                                         // For shortcuts with no component, keep them as they are        
2036                                         restoredRows.add(id);                                            
2037                                         restored = false;                                                
2038                                     }                                                                    
2039                                 } catch (URISyntaxException e) {                                         
2040                                     Launcher.addDumpLog(TAG,                                             
2041                                             "Invalid uri: " + intentDescription, true);                  
2042                                     continue;                                                            
2043                                 }                                                                        
2044                                                                                                          
2045                                 if (itemReplaced) {                                                      
2046                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
2047                                         info = getAppShortcutInfo(manager, intent, user, context, null,  
2048                                                 iconIndex, titleIndex, false);                           
2049                                     } else {                                                             
2050                                         // Don't replace items for other profiles.                       
2051                                         itemsToRemove.add(id);                                           
2052                                         continue;                                                        
2053                                     }                                                                    
2054                                 } else if (restored) {                                                   
2055                                     if (user.equals(UserHandleCompat.myUserHandle())) {                  
2056                                         Launcher.addDumpLog(TAG,                                         
2057                                                 "constructing info for partially restored package",      
2058                                                 true);                                                   
2059                                         info = getRestoredItemInfo(c, titleIndex, intent, promiseType);  
2060                                         intent = getRestoredItemIntent(c, context, intent);              
2061                                     } else {                                                             
2062                                         // Don't restore items for other profiles.                       
2063                                         itemsToRemove.add(id);                                           
2064                                         continue;                                                        
2065                                     }                                                                    
2066                                 } else if (itemType ==                                                   
2067                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {              
2068                                     info = getAppShortcutInfo(manager, intent, user, context, c,         
2069                                             iconIndex, titleIndex, allowMissingTarget);                  
2070                                 } else {                                                                 
2071                                     info = getShortcutInfo(c, context, iconTypeIndex,                    
2072                                             iconPackageIndex, iconResourceIndex, iconIndex,              
2073                                             titleIndex);                                                 
2074                                                                                                          
2075                                     // App shortcuts that used to be automatically added to Launcher     
2076                                     // didn't always have the correct intent flags set, so do that       
2077                                     // here                                                              
2078                                     if (intent.getAction() != null &&                                    
2079                                         intent.getCategories() != null &&                                
2080                                         intent.getAction().equals(Intent.ACTION_MAIN) &&                 
2081                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {     
2082                                         intent.addFlags(                                                 
2083                                             Intent.FLAG_ACTIVITY_NEW_TASK |                              
2084                                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                  
2085                                     }                                                                    
2086                                 }                                                                        
2087                                                                                                          
2088                                 if (info != null) {                                                      
2089                                     info.id = id;                                                        
2090                                     info.intent = intent;                                                
2091                                     container = c.getInt(containerIndex);                                
2092                                     info.container = container;                                          
2093                                     info.screenId = c.getInt(screenIndex);                               
2094                                     info.cellX = c.getInt(cellXIndex);                                   
2095                                     info.cellY = c.getInt(cellYIndex);                                   
2096                                     info.rank = c.getInt(rankIndex);                                     
2097                                     info.spanX = 1;                                                      
2098                                     info.spanY = 1;                                                      
2099                                     info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);          
2100                                     info.isDisabled = disabledState;                                     
2101                                     if (isSafeMode && !Utilities.isSystemApp(context, intent)) {         
2102                                         info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;          
2103                                     }                                                                    
2104                                                                                                          
2105                                     // check & update map of what's occupied                             
2106                                     if (!checkItemPlacement(occupied, info)) {                           
2107                                         itemsToRemove.add(id);                                           
2108                                         break;                                                           
2109                                     }                                                                    
2110                                                                                                          
2111                                     switch (container) {                                                 
2112                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2113                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2114                                         sBgWorkspaceItems.add(info);                                     
2115                                         break;                                                           
2116                                     default:                                                             
2117                                         // Item is in a user folder                                      
2118                                         FolderInfo folderInfo =                                          
2119                                                 findOrMakeFolder(sBgFolders, container);                 
2120                                         folderInfo.add(info);                                            
2121                                         break;                                                           
2122                                     }                                                                    
2123                                     sBgItemsIdMap.put(info.id, info);                                    
2124                                 } else {                                                                 
2125                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2126                                 }                                                                        
2127                                 break;                                                                   
2128                                                                                                          
2129                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2130                                 id = c.getLong(idIndex);                                                 
2131                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2132                                                                                                          
2133                                 folderInfo.title = c.getString(titleIndex);                              
2134                                 folderInfo.id = id;                                                      
2135                                 container = c.getInt(containerIndex);                                    
2136                                 folderInfo.container = container;                                        
2137                                 folderInfo.screenId = c.getInt(screenIndex);                             
2138                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2139                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2140                                 folderInfo.spanX = 1;                                                    
2141                                 folderInfo.spanY = 1;                                                    
2142                                                                                                          
2143                                 // check & update map of what's occupied                                 
2144                                 if (!checkItemPlacement(occupied, folderInfo)) {                         
2145                                     itemsToRemove.add(id);                                               
2146                                     break;                                                               
2147                                 }                                                                        
2148                                                                                                          
2149                                 switch (container) {                                                     
2150                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2151                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2152                                         sBgWorkspaceItems.add(folderInfo);                               
2153                                         break;                                                           
2154                                 }                                                                        
2155                                                                                                          
2156                                 if (restored) {                                                          
2157                                     // no special handling required for restored folders                 
2158                                     restoredRows.add(id);                                                
2159                                 }                                                                        
2160                                                                                                          
2161                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2162                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2163                                 break;                                                                   
2164                                                                                                          
2165                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2166                             case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                  
2167                                 // Read all Launcher-specific widget details                             
2168                                 boolean customWidget = itemType ==                                       
2169                                     LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;               
2170                                                                                                          
2171                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2172                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2173                                 id = c.getLong(idIndex);                                                 
2174                                 final ComponentName component =                                          
2175                                         ComponentName.unflattenFromString(savedProvider);                
2176                                                                                                          
2177                                 final int restoreStatus = c.getInt(restoredIndex);                       
2178                                 final boolean isIdValid = (restoreStatus &                               
2179                                         LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                   
2180                                                                                                          
2181                                 final boolean wasProviderReady = (restoreStatus &                        
2182                                         LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;             
2183                                                                                                          
2184                                 final LauncherAppWidgetProviderInfo provider =                           
2185                                         LauncherModel.getProviderInfo(context,                           
2186                                                 ComponentName.unflattenFromString(savedProvider));       
2187                                                                                                          
2188                                 final boolean isProviderReady = isValidProvider(provider);               
2189                                 if (!isSafeMode && !customWidget &&                                      
2190                                         wasProviderReady && !isProviderReady) {                          
2191                                     String log = "Deleting widget that isn't installed anymore: "        
2192                                             + "id=" + id + " appWidgetId=" + appWidgetId;                
2193                                                                                                          
2194                                     Log.e(TAG, log);                                                     
2195                                     Launcher.addDumpLog(TAG, log, false);                                
2196                                     itemsToRemove.add(id);                                               
2197                                 } else {                                                                 
2198                                     if (isProviderReady) {                                               
2199                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2200                                                 provider.provider);                                      
2201                                                                                                          
2202                                         if (!customWidget) {                                             
2203                                             int[] minSpan =                                              
2204                                                     Launcher.getMinSpanForWidget(context, provider);     
2205                                             appWidgetInfo.minSpanX = minSpan[0];                         
2206                                             appWidgetInfo.minSpanY = minSpan[1];                         
2207                                         }                                                                
2208                                                                                                          
2209                                         int status = restoreStatus;                                      
2210                                         if (!wasProviderReady) {                                         
2211                                             // If provider was not previously ready, update the          
2212                                             // status and UI flag.                                       
2213                                                                                                          
2214                                             // Id would be valid only if the widget restore broadcast was🔵
2215                                             if (isIdValid) {                                             
2216                                                 status = LauncherAppWidgetInfo.RESTORE_COMPLETED;        
2217                                             } else {                                                     
2218                                                 status &= ~LauncherAppWidgetInfo                         
2219                                                         .FLAG_PROVIDER_NOT_READY;                        
2220                                             }                                                            
2221                                         }                                                                
2222                                         appWidgetInfo.restoreStatus = status;                            
2223                                     } else {                                                             
2224                                         Log.v(TAG, "Widget restore pending id=" + id                     
2225                                                 + " appWidgetId=" + appWidgetId                          
2226                                                 + " status =" + restoreStatus);                          
2227                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,           
2228                                                 component);                                              
2229                                         appWidgetInfo.restoreStatus = restoreStatus;                     
2230                                                                                                          
2231                                         if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) 🔵
2232                                             // Restore has started once.                                 
2233                                         } else if (installingPkgs.contains(component.getPackageName())) {
2234                                             // App restore has started. Update the flag                  
2235                                             appWidgetInfo.restoreStatus |=                               
2236                                                     LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;          
2237                                         } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {             
2238                                             Launcher.addDumpLog(TAG,                                     
2239                                                     "Unrestored widget removed: " + component, true);    
2240                                             itemsToRemove.add(id);                                       
2241                                             continue;                                                    
2242                                         }                                                                
2243                                     }                                                                    
2244                                                                                                          
2245                                     appWidgetInfo.id = id;                                               
2246                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2247                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2248                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2249                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2250                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2251                                                                                                          
2252                                     if (!customWidget) {                                                 
2253                                         int[] minSpan = Launcher.getMinSpanForWidget(context, provider); 
2254                                         appWidgetInfo.minSpanX = minSpan[0];                             
2255                                         appWidgetInfo.minSpanY = minSpan[1];                             
2256                                     }                                                                    
2257                                                                                                          
2258                                     container = c.getInt(containerIndex);                                
2259                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2260                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2261                                         Log.e(TAG, "Widget found where container != " +                  
2262                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2263                                         continue;                                                        
2264                                     }                                                                    
2265                                                                                                          
2266                                     appWidgetInfo.container = c.getInt(containerIndex);                  
2267                                     // check & update map of what's occupied                             
2268                                     if (!checkItemPlacement(occupied, appWidgetInfo)) {                  
2269                                         itemsToRemove.add(id);                                           
2270                                         break;                                                           
2271                                     }                                                                    
2272                                                                                                          
2273                                     if (!customWidget) {                                                 
2274                                         String providerName =                                            
2275                                                 appWidgetInfo.providerName.flattenToString();            
2276                                         if (!providerName.equals(savedProvider) ||                       
2277                                                 (appWidgetInfo.restoreStatus != restoreStatus)) {        
2278                                             ContentValues values = new ContentValues();                  
2279                                             values.put(                                                  
2280                                                     LauncherSettings.Favorites.APPWIDGET_PROVIDER,       
2281                                                     providerName);                                       
2282                                             values.put(LauncherSettings.Favorites.RESTORED,              
2283                                                     appWidgetInfo.restoreStatus);                        
2284                                             updateItem(id, values);                                      
2285                                         }                                                                
2286                                     }                                                                    
2287                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2288                                     sBgAppWidgets.add(appWidgetInfo);                                    
2289                                 }                                                                        
2290                                 break;                                                                   
2291                             }                                                                            
2292                         } catch (Exception e) {                                                          
2293                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2294                         }                                                                                
2295                     }                                                                                    
2296                 } finally {                                                                              
2297                     if (c != null) {                                                                     
2298                         c.close();                                                                       
2299                     }                                                                                    
2300                 }                                                                                        
2301                                                                                                          
2302                 // Break early if we've stopped loading                                                  
2303                 if (mStopped) {                                                                          
2304                     clearSBgDataStructures();                                                            
2305                     return;                                                                              
2306                 }                                                                                        
2307                                                                                                          
2308                 if (itemsToRemove.size() > 0) {                                                          
2309                     ContentProviderClient client = contentResolver.acquireContentProviderClient(         
2310                             contentUri);                                                                 
2311                     // Remove dead items                                                                 
2312                     for (long id : itemsToRemove) {                                                      
2313                         if (DEBUG_LOADERS) {                                                             
2314                             Log.d(TAG, "Removed id = " + id);                                            
2315                         }                                                                                
2316                         // Don't notify content observers                                                
2317                         try {                                                                            
2318                             client.delete(LauncherSettings.Favorites.getContentUri(id, false),           
2319                                     null, null);                                                         
2320                         } catch (RemoteException e) {                                                    
2321                             Log.w(TAG, "Could not remove id = " + id);                                   
2322                         }                                                                                
2323                     }                                                                                    
2324                 }                                                                                        
2325                                                                                                          
2326                 if (restoredRows.size() > 0) {                                                           
2327                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(        
2328                             contentUri);                                                                 
2329                     // Update restored items that no longer require special handling                     
2330                     try {                                                                                
2331                         StringBuilder selectionBuilder = new StringBuilder();                            
2332                         selectionBuilder.append(LauncherSettings.Favorites._ID);                         
2333                         selectionBuilder.append(" IN (");                                                
2334                         selectionBuilder.append(TextUtils.join(", ", restoredRows));                     
2335                         selectionBuilder.append(")");                                                    
2336                         ContentValues values = new ContentValues();                                      
2337                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2338                         updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,           
2339                                 values, selectionBuilder.toString(), null);                              
2340                     } catch (RemoteException e) {                                                        
2341                         Log.w(TAG, "Could not update restored rows");                                    
2342                     }                                                                                    
2343                 }                                                                                        
2344                                                                                                          
2345                 if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                     
2346                     context.registerReceiver(new AppsAvailabilityCheck(),                                
2347                             new IntentFilter(StartupReceiver.SYSTEM_READY),                              
2348                             null, sWorker);                                                              
2349                 }                                                                                        
2350                                                                                                          
2351                 sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                            
2352                 // Log to disk                                                                           
2353                 Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                          
2354                         TextUtils.join(", ", sBgWorkspaceScreens), true);                                
2355                                                                                                          
2356                 // Remove any empty screens                                                              
2357                 ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                
2358                 for (ItemInfo item: sBgItemsIdMap.values()) {                                            
2359                     long screenId = item.screenId;                                                       
2360                     if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                
2361                             unusedScreens.contains(screenId)) {                                          
2362                         unusedScreens.remove(screenId);                                                  
2363                     }                                                                                    
2364                 }                                                                                        
2365                                                                                                          
2366                 // If there are any empty screens remove them, and update.                               
2367                 if (unusedScreens.size() != 0) {                                                         
2368                     // Log to disk                                                                       
2369                     Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +            
2370                             TextUtils.join(", ", unusedScreens), true);                                  
2371                                                                                                          
2372                     sBgWorkspaceScreens.removeAll(unusedScreens);                                        
2373                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2374                 }                                                                                        
2375                                                                                                          
2376                 if (DEBUG_LOADERS) {                                                                     
2377                     Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");          
2378                     Log.d(TAG, "workspace layout: ");                                                    
2379                     int nScreens = occupied.size();                                                      
2380                     for (int y = 0; y < countY; y++) {                                                   
2381                         String line = "";                                                                
2382                                                                                                          
2383                         Iterator<Long> iter = occupied.keySet().iterator();                              
2384                         while (iter.hasNext()) {                                                         
2385                             long screenId = iter.next();                                                 
2386                             if (screenId > 0) {                                                          
2387                                 line += " | ";                                                           
2388                             }                                                                            
2389                             for (int x = 0; x < countX; x++) {                                           
2390                                 ItemInfo[][] screen = occupied.get(screenId);                            
2391                                 if (x < screen.length && y < screen[x].length) {                         
2392                                     line += (screen[x][y] != null) ? "#" : ".";                          
2393                                 } else {                                                                 
2394                                     line += "!";                                                         
2395                                 }                                                                        
2396                             }                                                                            
2397                         }                                                                                
2398                         Log.d(TAG, "[ " + line + " ]");                                                  
2399                     }                                                                                    
2400                 }                                                                                        
2401             }                                                                                            
2402         }                                                                                                
2403                                                                                                          
2404         /**                                                                                              
2405          * Partially updates the item without any notification. Must be called on the worker thread.     
2406          */                                                                                              
2407         private void updateItem(long itemId, ContentValues update) {                                     
2408             mContext.getContentResolver().update(                                                        
2409                     LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                              
2410                     update,                                                                              
2411                     BaseColumns._ID + "= ?",                                                             
2412                     new String[]{Long.toString(itemId)});                                                
2413         }                                                                                                
2414                                                                                                          
2415         /** Filters the set of items who are directly or indirectly (via another container) on the       
2416          * specified screen. */                                                                          
2417         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2418                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2419                 ArrayList<ItemInfo> currentScreenItems,                                                  
2420                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2421             // Purge any null ItemInfos                                                                  
2422             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2423             while (iter.hasNext()) {                                                                     
2424                 ItemInfo i = iter.next();                                                                
2425                 if (i == null) {                                                                         
2426                     iter.remove();                                                                       
2427                 }                                                                                        
2428             }                                                                                            
2429                                                                                                          
2430             // Order the set of items by their containers first, this allows use to walk through the     
2431             // list sequentially, build up a list of containers that are in the specified screen,        
2432             // as well as all items in those containers.                                                 
2433             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2434             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2435                 @Override                                                                                
2436                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2437                     return (int) (lhs.container - rhs.container);                                        
2438                 }                                                                                        
2439             });                                                                                          
2440             for (ItemInfo info : allWorkspaceItems) {                                                    
2441                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2442                     if (info.screenId == currentScreenId) {                                              
2443                         currentScreenItems.add(info);                                                    
2444                         itemsOnScreen.add(info.id);                                                      
2445                     } else {                                                                             
2446                         otherScreenItems.add(info);                                                      
2447                     }                                                                                    
2448                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2449                     currentScreenItems.add(info);                                                        
2450                     itemsOnScreen.add(info.id);                                                          
2451                 } else {                                                                                 
2452                     if (itemsOnScreen.contains(info.container)) {                                        
2453                         currentScreenItems.add(info);                                                    
2454                         itemsOnScreen.add(info.id);                                                      
2455                     } else {                                                                             
2456                         otherScreenItems.add(info);                                                      
2457                     }                                                                                    
2458                 }                                                                                        
2459             }                                                                                            
2460         }                                                                                                
2461                                                                                                          
2462         /** Filters the set of widgets which are on the specified screen. */                             
2463         private void filterCurrentAppWidgets(long currentScreenId,                                       
2464                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2465                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2466                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2467                                                                                                          
2468             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2469                 if (widget == null) continue;                                                            
2470                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2471                         widget.screenId == currentScreenId) {                                            
2472                     currentScreenWidgets.add(widget);                                                    
2473                 } else {                                                                                 
2474                     otherScreenWidgets.add(widget);                                                      
2475                 }                                                                                        
2476             }                                                                                            
2477         }                                                                                                
2478                                                                                                          
2479         /** Filters the set of folders which are on the specified screen. */                             
2480         private void filterCurrentFolders(long currentScreenId,                                          
2481                 HashMap<Long, ItemInfo> itemsIdMap,                                                      
2482                 HashMap<Long, FolderInfo> folders,                                                       
2483                 HashMap<Long, FolderInfo> currentScreenFolders,                                          
2484                 HashMap<Long, FolderInfo> otherScreenFolders) {                                          
2485                                                                                                          
2486             for (long id : folders.keySet()) {                                                           
2487                 ItemInfo info = itemsIdMap.get(id);                                                      
2488                 FolderInfo folder = folders.get(id);                                                     
2489                 if (info == null || folder == null) continue;                                            
2490                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2491                         info.screenId == currentScreenId) {                                              
2492                     currentScreenFolders.put(id, folder);                                                
2493                 } else {                                                                                 
2494                     otherScreenFolders.put(id, folder);                                                  
2495                 }                                                                                        
2496             }                                                                                            
2497         }                                                                                                
2498                                                                                                          
2499         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2500          * right) */                                                                                     
2501         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2502             final LauncherAppState app = LauncherAppState.getInstance();                                 
2503             final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                          
2504             // XXX: review this                                                                          
2505             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2506                 @Override                                                                                
2507                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2508                     int cellCountX = (int) grid.numColumns;                                              
2509                     int cellCountY = (int) grid.numRows;                                                 
2510                     int screenOffset = cellCountX * cellCountY;                                          
2511                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2512                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2513                             lhs.cellY * cellCountX + lhs.cellX);                                         
2514                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2515                             rhs.cellY * cellCountX + rhs.cellX);                                         
2516                     return (int) (lr - rr);                                                              
2517                 }                                                                                        
2518             });                                                                                          
2519         }                                                                                                
2520                                                                                                          
2521         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2522                 final ArrayList<Long> orderedScreens) {                                                  
2523             final Runnable r = new Runnable() {                                                          
2524                 @Override                                                                                
2525                 public void run() {                                                                      
2526                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2527                     if (callbacks != null) {                                                             
2528                         callbacks.bindScreens(orderedScreens);                                           
2529                     }                                                                                    
2530                 }                                                                                        
2531             };                                                                                           
2532             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2533         }                                                                                                
2534                                                                                                          
2535         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2536                 final ArrayList<ItemInfo> workspaceItems,                                                
2537                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2538                 final HashMap<Long, FolderInfo> folders,                                                 
2539                 ArrayList<Runnable> deferredBindRunnables) {                                             
2540                                                                                                          
2541             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2542                                                                                                          
2543             // Bind the workspace items                                                                  
2544             int N = workspaceItems.size();                                                               
2545             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2546                 final int start = i;                                                                     
2547                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2548                 final Runnable r = new Runnable() {                                                      
2549                     @Override                                                                            
2550                     public void run() {                                                                  
2551                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2552                         if (callbacks != null) {                                                         
2553                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2554                                     false);                                                              
2555                         }                                                                                
2556                     }                                                                                    
2557                 };                                                                                       
2558                 if (postOnMainThread) {                                                                  
2559                     synchronized (deferredBindRunnables) {                                               
2560                         deferredBindRunnables.add(r);                                                    
2561                     }                                                                                    
2562                 } else {                                                                                 
2563                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2564                 }                                                                                        
2565             }                                                                                            
2566                                                                                                          
2567             // Bind the folders                                                                          
2568             if (!folders.isEmpty()) {                                                                    
2569                 final Runnable r = new Runnable() {                                                      
2570                     public void run() {                                                                  
2571                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2572                         if (callbacks != null) {                                                         
2573                             callbacks.bindFolders(folders);                                              
2574                         }                                                                                
2575                     }                                                                                    
2576                 };                                                                                       
2577                 if (postOnMainThread) {                                                                  
2578                     synchronized (deferredBindRunnables) {                                               
2579                         deferredBindRunnables.add(r);                                                    
2580                     }                                                                                    
2581                 } else {                                                                                 
2582                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2583                 }                                                                                        
2584             }                                                                                            
2585                                                                                                          
2586             // Bind the widgets, one at a time                                                           
2587             N = appWidgets.size();                                                                       
2588             for (int i = 0; i < N; i++) {                                                                
2589                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2590                 final Runnable r = new Runnable() {                                                      
2591                     public void run() {                                                                  
2592                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2593                         if (callbacks != null) {                                                         
2594                             callbacks.bindAppWidget(widget);                                             
2595                         }                                                                                
2596                     }                                                                                    
2597                 };                                                                                       
2598                 if (postOnMainThread) {                                                                  
2599                     deferredBindRunnables.add(r);                                                        
2600                 } else {                                                                                 
2601                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2602                 }                                                                                        
2603             }                                                                                            
2604         }                                                                                                
2605                                                                                                          
2606         /**                                                                                              
2607          * Binds all loaded data to actual views on the main thread.                                     
2608          */                                                                                              
2609         private void bindWorkspace(int synchronizeBindPage) {                                            
2610             final long t = SystemClock.uptimeMillis();                                                   
2611             Runnable r;                                                                                  
2612                                                                                                          
2613             // Don't use these two variables in any of the callback runnables.                           
2614             // Otherwise we hold a reference to them.                                                    
2615             final Callbacks oldCallbacks = mCallbacks.get();                                             
2616             if (oldCallbacks == null) {                                                                  
2617                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2618                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2619                 return;                                                                                  
2620             }                                                                                            
2621                                                                                                          
2622             // Save a copy of all the bg-thread collections                                              
2623             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2624             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2625                     new ArrayList<LauncherAppWidgetInfo>();                                              
2626             HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                         
2627             HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                          
2628             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2629             synchronized (sBgLock) {                                                                     
2630                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2631                 appWidgets.addAll(sBgAppWidgets);                                                        
2632                 folders.putAll(sBgFolders);                                                              
2633                 itemsIdMap.putAll(sBgItemsIdMap);                                                        
2634                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2635             }                                                                                            
2636                                                                                                          
2637             final boolean isLoadingSynchronously =                                                       
2638                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2639             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2640                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2641             if (currScreen >= orderedScreenIds.size()) {                                                 
2642                 // There may be no workspace screens (just hotseat items and an empty page).             
2643                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2644             }                                                                                            
2645             final int currentScreen = currScreen;                                                        
2646             final long currentScreenId = currentScreen < 0                                               
2647                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2648                                                                                                          
2649             // Load all the items that are on the current page first (and in the process, unbind         
2650             // all the existing workspace items before we call startBinding() below.                     
2651             unbindWorkspaceItemsOnMainThread();                                                          
2652                                                                                                          
2653             // Separate the items that are on the current screen, and all the other remaining items      
2654             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2655             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2656             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2657                     new ArrayList<LauncherAppWidgetInfo>();                                              
2658             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2659                     new ArrayList<LauncherAppWidgetInfo>();                                              
2660             HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                  
2661             HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                    
2662                                                                                                          
2663             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2664                     otherWorkspaceItems);                                                                
2665             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2666                     otherAppWidgets);                                                                    
2667             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2668                     otherFolders);                                                                       
2669             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2670             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2671                                                                                                          
2672             // Tell the workspace that we're about to start binding items                                
2673             r = new Runnable() {                                                                         
2674                 public void run() {                                                                      
2675                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2676                     if (callbacks != null) {                                                             
2677                         callbacks.startBinding();                                                        
2678                     }                                                                                    
2679                 }                                                                                        
2680             };                                                                                           
2681             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2682                                                                                                          
2683             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2684                                                                                                          
2685             // Load items on the current page                                                            
2686             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2687                     currentFolders, null);                                                               
2688             if (isLoadingSynchronously) {                                                                
2689                 r = new Runnable() {                                                                     
2690                     public void run() {                                                                  
2691                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2692                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2693                             callbacks.onPageBoundSynchronously(currentScreen);                           
2694                         }                                                                                
2695                     }                                                                                    
2696                 };                                                                                       
2697                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2698             }                                                                                            
2699                                                                                                          
2700             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2701             // work until after the first render)                                                        
2702             synchronized (mDeferredBindRunnables) {                                                      
2703                 mDeferredBindRunnables.clear();                                                          
2704             }                                                                                            
2705             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2706                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2707                                                                                                          
2708             // Tell the workspace that we're done binding items                                          
2709             r = new Runnable() {                                                                         
2710                 public void run() {                                                                      
2711                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2712                     if (callbacks != null) {                                                             
2713                         callbacks.finishBindingItems();                                                  
2714                     }                                                                                    
2715                                                                                                          
2716                     // If we're profiling, ensure this is the last thing in the queue.                   
2717                     if (DEBUG_LOADERS) {                                                                 
2718                         Log.d(TAG, "bound workspace in "                                                 
2719                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2720                     }                                                                                    
2721                                                                                                          
2722                     mIsLoadingAndBindingWorkspace = false;                                               
2723                 }                                                                                        
2724             };                                                                                           
2725             if (isLoadingSynchronously) {                                                                
2726                 synchronized (mDeferredBindRunnables) {                                                  
2727                     mDeferredBindRunnables.add(r);                                                       
2728                 }                                                                                        
2729             } else {                                                                                     
2730                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2731             }                                                                                            
2732         }                                                                                                
2733                                                                                                          
2734         private void loadAndBindAllApps() {                                                              
2735             if (DEBUG_LOADERS) {                                                                         
2736                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2737             }                                                                                            
2738             if (!mAllAppsLoaded) {                                                                       
2739                 loadAllApps();                                                                           
2740                 synchronized (LoaderTask.this) {                                                         
2741                     if (mStopped) {                                                                      
2742                         return;                                                                          
2743                     }                                                                                    
2744                     mAllAppsLoaded = true;                                                               
2745                 }                                                                                        
2746             } else {                                                                                     
2747                 onlyBindAllApps();                                                                       
2748             }                                                                                            
2749         }                                                                                                
2750                                                                                                          
2751         private void onlyBindAllApps() {                                                                 
2752             final Callbacks oldCallbacks = mCallbacks.get();                                             
2753             if (oldCallbacks == null) {                                                                  
2754                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2755                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2756                 return;                                                                                  
2757             }                                                                                            
2758                                                                                                          
2759             // shallow copy                                                                              
2760             @SuppressWarnings("unchecked")                                                               
2761             final ArrayList<AppInfo> list                                                                
2762                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2763             Runnable r = new Runnable() {                                                                
2764                 public void run() {                                                                      
2765                     final long t = SystemClock.uptimeMillis();                                           
2766                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2767                     if (callbacks != null) {                                                             
2768                         callbacks.bindAllApplications(list);                                             
2769                     }                                                                                    
2770                     if (DEBUG_LOADERS) {                                                                 
2771                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2772                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2773                     }                                                                                    
2774                 }                                                                                        
2775             };                                                                                           
2776             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2777             if (isRunningOnMainThread) {                                                                 
2778                 r.run();                                                                                 
2779             } else {                                                                                     
2780                 mHandler.post(r);                                                                        
2781             }                                                                                            
2782         }                                                                                                
2783                                                                                                          
2784         private void loadAllApps() {                                                                     
2785             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2786                                                                                                          
2787             final Callbacks oldCallbacks = mCallbacks.get();                                             
2788             if (oldCallbacks == null) {                                                                  
2789                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2790                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2791                 return;                                                                                  
2792             }                                                                                            
2793                                                                                                          
2794             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                              
2795             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                            
2796                                                                                                          
2797             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                      
2798                                                                                                          
2799             // Clear the list of apps                                                                    
2800             mBgAllAppsList.clear();                                                                      
2801             SharedPreferences prefs = mContext.getSharedPreferences(                                     
2802                     LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                   
2803             for (UserHandleCompat user : profiles) {                                                     
2804                 // Query for the set of apps                                                             
2805                 final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                     
2806                 List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);       
2807                 if (DEBUG_LOADERS) {                                                                     
2808                     Log.d(TAG, "getActivityList took "                                                   
2809                             + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);             
2810                     Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);         
2811                 }                                                                                        
2812                 // Fail if we don't have any apps                                                        
2813                 // TODO: Fix this. Only fail for the current user.                                       
2814                 if (apps == null || apps.isEmpty()) {                                                    
2815                     return;                                                                              
2816                 }                                                                                        
2817                                                                                                          
2818                 // Update icon cache                                                                     
2819                 HashSet<String> updatedPackages = mIconCache.updateDBIcons(user, apps);                  
2820                                                                                                          
2821                 // If any package icon has changed (app was updated while launcher was dead),            
2822                 // update the corresponding shortcuts.                                                   
2823                 if (!updatedPackages.isEmpty()) {                                                        
2824                     final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();               
2825                     synchronized (sBgLock) {                                                             
2826                         for (ItemInfo info : sBgItemsIdMap.values()) {                                   
2827                             if (info instanceof ShortcutInfo && user.equals(info.user)                   
2828                                     && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION)🔵
2829                                 ShortcutInfo si = (ShortcutInfo) info;                                   
2830                                 ComponentName cn = si.getTargetComponent();                              
2831                                 if (cn != null && updatedPackages.contains(cn.getPackageName())) {       
2832                                     si.updateIcon(mIconCache);                                           
2833                                     updates.add(si);                                                     
2834                                 }                                                                        
2835                             }                                                                            
2836                         }                                                                                
2837                     }                                                                                    
2838                                                                                                          
2839                     if (!updates.isEmpty()) {                                                            
2840                         final UserHandleCompat userFinal = user;                                         
2841                         mHandler.post(new Runnable() {                                                   
2842                                                                                                          
2843                             public void run() {                                                          
2844                                 Callbacks cb = getCallback();                                            
2845                                 if (cb != null) {                                                        
2846                                     cb.bindShortcutsChanged(                                             
2847                                             updates, new ArrayList<ShortcutInfo>(), userFinal);          
2848                                 }                                                                        
2849                             }                                                                            
2850                         });                                                                              
2851                     }                                                                                    
2852                 }                                                                                        
2853                                                                                                          
2854                 // Create the ApplicationInfos                                                           
2855                 for (int i = 0; i < apps.size(); i++) {                                                  
2856                     LauncherActivityInfoCompat app = apps.get(i);                                        
2857                     // This builds the icon bitmaps.                                                     
2858                     mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                    
2859                 }                                                                                        
2860                                                                                                          
2861                 if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {    
2862                     // Add shortcuts for packages which were installed while launcher was dead.          
2863                     String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                              
2864                             + mUserManager.getSerialNumberForUser(user);                                 
2865                     Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET🔵
2866                     HashSet<String> newPackageSet = new HashSet<String>();                               
2867                                                                                                          
2868                     for (LauncherActivityInfoCompat info : apps) {                                       
2869                         String packageName = info.getComponentName().getPackageName();                   
2870                         if (!packagesAdded.contains(packageName)                                         
2871                                 && !newPackageSet.contains(packageName)) {                               
2872                             InstallShortcutReceiver.queueInstallShortcut(info, mContext);                
2873                         }                                                                                
2874                         newPackageSet.add(packageName);                                                  
2875                     }                                                                                    
2876                                                                                                          
2877                     prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                  
2878                 }                                                                                        
2879             }                                                                                            
2880             // Huh? Shouldn't this be inside the Runnable below?                                         
2881             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2882             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2883                                                                                                          
2884             // Post callback on main thread                                                              
2885             mHandler.post(new Runnable() {                                                               
2886                 public void run() {                                                                      
2887                     final long bindTime = SystemClock.uptimeMillis();                                    
2888                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2889                     if (callbacks != null) {                                                             
2890                         callbacks.bindAllApplications(added);                                            
2891                         if (DEBUG_LOADERS) {                                                             
2892                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2893                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2894                         }                                                                                
2895                     } else {                                                                             
2896                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2897                     }                                                                                    
2898                 }                                                                                        
2899             });                                                                                          
2900                                                                                                          
2901             if (DEBUG_LOADERS) {                                                                         
2902                 Log.d(TAG, "Icons processed in "                                                         
2903                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2904             }                                                                                            
2905         }                                                                                                
2906                                                                                                          
2907         public void dumpState() {                                                                        
2908             synchronized (sBgLock) {                                                                     
2909                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2910                 Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                  
2911                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2912                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2913                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2914             }                                                                                            
2915         }                                                                                                
2916     }                                                                                                    
2917                                                                                                          
2918     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2919         sWorker.post(task);                                                                              
2920     }                                                                                                    
2921                                                                                                          
2922     private class AppsAvailabilityCheck extends BroadcastReceiver {                                      
2923                                                                                                          
2924         @Override                                                                                        
2925         public void onReceive(Context context, Intent intent) {                                          
2926             synchronized (sBgLock) {                                                                     
2927                 final LauncherAppsCompat launcherApps = LauncherAppsCompat                               
2928                         .getInstance(mApp.getContext());                                                 
2929                 final PackageManager manager = context.getPackageManager();                              
2930                 final ArrayList<String> packagesRemoved = new ArrayList<String>();                       
2931                 final ArrayList<String> packagesUnavailable = new ArrayList<String>();                   
2932                 for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {     
2933                     UserHandleCompat user = entry.getKey();                                              
2934                     packagesRemoved.clear();                                                             
2935                     packagesUnavailable.clear();                                                         
2936                     for (String pkg : entry.getValue()) {                                                
2937                         if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                       
2938                             boolean packageOnSdcard = launcherApps.isAppEnabled(                         
2939                                     manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);              
2940                             if (packageOnSdcard) {                                                       
2941                                 Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);      
2942                                 packagesUnavailable.add(pkg);                                            
2943                             } else {                                                                     
2944                                 Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);             
2945                                 packagesRemoved.add(pkg);                                                
2946                             }                                                                            
2947                         }                                                                                
2948                     }                                                                                    
2949                     if (!packagesRemoved.isEmpty()) {                                                    
2950                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,       
2951                                 packagesRemoved.toArray(new String[packagesRemoved.size()]), user));     
2952                     }                                                                                    
2953                     if (!packagesUnavailable.isEmpty()) {                                                
2954                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,  
2955                                 packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user🔵
2956                     }                                                                                    
2957                 }                                                                                        
2958                 sPendingPackages.clear();                                                                
2959             }                                                                                            
2960         }                                                                                                
2961     }                                                                                                    
2962                                                                                                          
2963     private class PackageUpdatedTask implements Runnable {                                               
2964         int mOp;                                                                                         
2965         String[] mPackages;                                                                              
2966         UserHandleCompat mUser;                                                                          
2967                                                                                                          
2968         public static final int OP_NONE = 0;                                                             
2969         public static final int OP_ADD = 1;                                                              
2970         public static final int OP_UPDATE = 2;                                                           
2971         public static final int OP_REMOVE = 3; // uninstlled                                             
2972         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2973                                                                                                          
2974                                                                                                          
2975         public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                    
2976             mOp = op;                                                                                    
2977             mPackages = packages;                                                                        
2978             mUser = user;                                                                                
2979         }                                                                                                
2980                                                                                                          
2981         public void run() {                                                                              
2982             final Context context = mApp.getContext();                                                   
2983                                                                                                          
2984             final String[] packages = mPackages;                                                         
2985             final int N = packages.length;                                                               
2986             switch (mOp) {                                                                               
2987                 case OP_ADD:                                                                             
2988                     for (int i=0; i<N; i++) {                                                            
2989                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);         
2990                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
2991                         mBgAllAppsList.addPackage(context, packages[i], mUser);                          
2992                     }                                                                                    
2993                                                                                                          
2994                     // Auto add shortcuts for added packages.                                            
2995                     if (ADD_MANAGED_PROFILE_SHORTCUTS                                                    
2996                             && !UserHandleCompat.myUserHandle().equals(mUser)) {                         
2997                         SharedPreferences prefs = context.getSharedPreferences(                          
2998                                 LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);       
2999                         String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                          
3000                                 + mUserManager.getSerialNumberForUser(mUser);                            
3001                         Set<String> shortcutSet = new HashSet<String>(                                   
3002                                 prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));              
3003                                                                                                          
3004                         for (int i=0; i<N; i++) {                                                        
3005                             if (!shortcutSet.contains(packages[i])) {                                    
3006                                 shortcutSet.add(packages[i]);                                            
3007                                 List<LauncherActivityInfoCompat> activities =                            
3008                                         mLauncherApps.getActivityList(packages[i], mUser);               
3009                                 if (activities != null && !activities.isEmpty()) {                       
3010                                     InstallShortcutReceiver.queueInstallShortcut(                        
3011                                             activities.get(0), context);                                 
3012                                 }                                                                        
3013                             }                                                                            
3014                         }                                                                                
3015                                                                                                          
3016                         prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                
3017                     }                                                                                    
3018                     break;                                                                               
3019                 case OP_UPDATE:                                                                          
3020                     for (int i=0; i<N; i++) {                                                            
3021                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);      
3022                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
3023                         mBgAllAppsList.updatePackage(context, packages[i], mUser);                       
3024                         WidgetPreviewLoader.removePackageFromDb(                                         
3025                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
3026                     }                                                                                    
3027                     break;                                                                               
3028                 case OP_REMOVE:                                                                          
3029                     // Remove the packageName for the set of auto-installed shortcuts. This              
3030                     // will ensure that the shortcut when the app is installed again.                    
3031                     if (ADD_MANAGED_PROFILE_SHORTCUTS                                                    
3032                             && !UserHandleCompat.myUserHandle().equals(mUser)) {                         
3033                         SharedPreferences prefs = context.getSharedPreferences(                          
3034                                 LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);       
3035                         String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                          
3036                                 + mUserManager.getSerialNumberForUser(mUser);                            
3037                         HashSet<String> shortcutSet = new HashSet<String>(                               
3038                                 prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));             
3039                         shortcutSet.removeAll(Arrays.asList(mPackages));                                 
3040                         prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                
3041                     }                                                                                    
3042                     for (int i=0; i<N; i++) {                                                            
3043                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3044                         mIconCache.removeIconsForPkg(packages[i], mUser);                                
3045                     }                                                                                    
3046                     // Fall through                                                                      
3047                 case OP_UNAVAILABLE:                                                                     
3048                     for (int i=0; i<N; i++) {                                                            
3049                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
3050                         mBgAllAppsList.removePackage(packages[i], mUser);                                
3051                         WidgetPreviewLoader.removePackageFromDb(                                         
3052                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
3053                     }                                                                                    
3054                     break;                                                                               
3055             }                                                                                            
3056                                                                                                          
3057             ArrayList<AppInfo> added = null;                                                             
3058             ArrayList<AppInfo> modified = null;                                                          
3059             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
3060                                                                                                          
3061             if (mBgAllAppsList.added.size() > 0) {                                                       
3062                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
3063                 mBgAllAppsList.added.clear();                                                            
3064             }                                                                                            
3065             if (mBgAllAppsList.modified.size() > 0) {                                                    
3066                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
3067                 mBgAllAppsList.modified.clear();                                                         
3068             }                                                                                            
3069             if (mBgAllAppsList.removed.size() > 0) {                                                     
3070                 removedApps.addAll(mBgAllAppsList.removed);                                              
3071                 mBgAllAppsList.removed.clear();                                                          
3072             }                                                                                            
3073                                                                                                          
3074             final Callbacks callbacks = getCallback();                                                   
3075             if (callbacks == null) {                                                                     
3076                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
3077                 return;                                                                                  
3078             }                                                                                            
3079                                                                                                          
3080             final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                   
3081                     new HashMap<ComponentName, AppInfo>();                                               
3082                                                                                                          
3083             if (added != null) {                                                                         
3084                     addAppsToAllApps(context, added);                                                    
3085                 for (AppInfo ai : added) {                                                               
3086                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3087                 }                                                                                        
3088             }                                                                                            
3089                                                                                                          
3090             if (modified != null) {                                                                      
3091                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
3092                 for (AppInfo ai : modified) {                                                            
3093                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
3094                 }                                                                                        
3095                                                                                                          
3096                 mHandler.post(new Runnable() {                                                           
3097                     public void run() {                                                                  
3098                         Callbacks cb = getCallback();                                                    
3099                         if (callbacks == cb && cb != null) {                                             
3100                             callbacks.bindAppsUpdated(modifiedFinal);                                    
3101                         }                                                                                
3102                     }                                                                                    
3103                 });                                                                                      
3104             }                                                                                            
3105                                                                                                          
3106             // Update shortcut infos                                                                     
3107             if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                     
3108                 final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();          
3109                 final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();          
3110                 final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>(); 
3111                                                                                                          
3112                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));               
3113                 synchronized (sBgLock) {                                                                 
3114                     for (ItemInfo info : sBgItemsIdMap.values()) {                                       
3115                         if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                   
3116                             ShortcutInfo si = (ShortcutInfo) info;                                       
3117                             boolean infoUpdated = false;                                                 
3118                             boolean shortcutUpdated = false;                                             
3119                                                                                                          
3120                             // Update shortcuts which use iconResource.                                  
3121                             if ((si.iconResource != null)                                                
3122                                     && packageSet.contains(si.iconResource.packageName)) {               
3123                                 Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,    
3124                                         si.iconResource.resourceName, mIconCache, context);              
3125                                 if (icon != null) {                                                      
3126                                     si.setIcon(icon);                                                    
3127                                     si.usingFallbackIcon = false;                                        
3128                                     infoUpdated = true;                                                  
3129                                 }                                                                        
3130                             }                                                                            
3131                                                                                                          
3132                             ComponentName cn = si.getTargetComponent();                                  
3133                             if (cn != null && packageSet.contains(cn.getPackageName())) {                
3134                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);                            
3135                                                                                                          
3136                                 if (si.isPromise()) {                                                    
3137                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {           
3138                                         // Auto install icon                                             
3139                                         PackageManager pm = context.getPackageManager();                 
3140                                         ResolveInfo matched = pm.resolveActivity(                        
3141                                                 new Intent(Intent.ACTION_MAIN)                           
3142                                                 .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER), 
3143                                                 PackageManager.MATCH_DEFAULT_ONLY);                      
3144                                         if (matched == null) {                                           
3145                                             // Try to find the best match activity.                      
3146                                             Intent intent = pm.getLaunchIntentForPackage(                
3147                                                     cn.getPackageName());                                
3148                                             if (intent != null) {                                        
3149                                                 cn = intent.getComponent();                              
3150                                                 appInfo = addedOrUpdatedApps.get(cn);                    
3151                                             }                                                            
3152                                                                                                          
3153                                             if ((intent == null) || (appInfo == null)) {                 
3154                                                 removedShortcuts.add(si);                                
3155                                                 continue;                                                
3156                                             }                                                            
3157                                             si.promisedIntent = intent;                                  
3158                                         }                                                                
3159                                     }                                                                    
3160                                                                                                          
3161                                     // Restore the shortcut.                                             
3162                                     si.intent = si.promisedIntent;                                       
3163                                     si.promisedIntent = null;                                            
3164                                     si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                        
3165                                             & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                         
3166                                             & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                 
3167                                                                                                          
3168                                     infoUpdated = true;                                                  
3169                                     si.updateIcon(mIconCache);                                           
3170                                 }                                                                        
3171                                                                                                          
3172                                 if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())  
3173                                         && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATIO🔵
3174                                     si.updateIcon(mIconCache);                                           
3175                                     si.title = appInfo.title.toString();                                 
3176                                     si.contentDescription = appInfo.contentDescription;                  
3177                                     infoUpdated = true;                                                  
3178                                 }                                                                        
3179                                                                                                          
3180                                 if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {   
3181                                     // Since package was just updated, the target must be available now. 
3182                                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;          
3183                                     shortcutUpdated = true;                                              
3184                                 }                                                                        
3185                             }                                                                            
3186                                                                                                          
3187                             if (infoUpdated || shortcutUpdated) {                                        
3188                                 updatedShortcuts.add(si);                                                
3189                             }                                                                            
3190                             if (infoUpdated) {                                                           
3191                                 updateItemInDatabase(context, si);                                       
3192                             }                                                                            
3193                         } else if (info instanceof LauncherAppWidgetInfo) {                              
3194                             LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;             
3195                             if (mUser.equals(widgetInfo.user)                                            
3196                                     && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_🔵
3197                                     && packageSet.contains(widgetInfo.providerName.getPackageName())) {  
3198                                 widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READ🔵
3199                                 widgets.add(widgetInfo);                                                 
3200                                 updateItemInDatabase(context, widgetInfo);                               
3201                             }                                                                            
3202                         }                                                                                
3203                     }                                                                                    
3204                 }                                                                                        
3205                                                                                                          
3206                 if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                        
3207                     mHandler.post(new Runnable() {                                                       
3208                                                                                                          
3209                         public void run() {                                                              
3210                             Callbacks cb = getCallback();                                                
3211                             if (callbacks == cb && cb != null) {                                         
3212                                 callbacks.bindShortcutsChanged(                                          
3213                                         updatedShortcuts, removedShortcuts, mUser);                      
3214                             }                                                                            
3215                         }                                                                                
3216                     });                                                                                  
3217                     if (!removedShortcuts.isEmpty()) {                                                   
3218                         deleteItemsFromDatabase(context, removedShortcuts);                              
3219                     }                                                                                    
3220                 }                                                                                        
3221                 if (!widgets.isEmpty()) {                                                                
3222                     mHandler.post(new Runnable() {                                                       
3223                         public void run() {                                                              
3224                             Callbacks cb = getCallback();                                                
3225                             if (callbacks == cb && cb != null) {                                         
3226                                 callbacks.bindWidgetsRestored(widgets);                                  
3227                             }                                                                            
3228                         }                                                                                
3229                     });                                                                                  
3230                 }                                                                                        
3231             }                                                                                            
3232                                                                                                          
3233             final ArrayList<String> removedPackageNames =                                                
3234                     new ArrayList<String>();                                                             
3235             if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                             
3236                 // Mark all packages in the broadcast to be removed                                      
3237                 removedPackageNames.addAll(Arrays.asList(packages));                                     
3238             } else if (mOp == OP_UPDATE) {                                                               
3239                 // Mark disabled packages in the broadcast to be removed                                 
3240                 for (int i=0; i<N; i++) {                                                                
3241                     if (isPackageDisabled(context, packages[i], mUser)) {                                
3242                         removedPackageNames.add(packages[i]);                                            
3243                     }                                                                                    
3244                 }                                                                                        
3245             }                                                                                            
3246                                                                                                          
3247             if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                              
3248                 final int removeReason;                                                                  
3249                 if (mOp == OP_UNAVAILABLE) {                                                             
3250                     removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                             
3251                 } else {                                                                                 
3252                     // Remove all the components associated with this package                            
3253                     for (String pn : removedPackageNames) {                                              
3254                         deletePackageFromDatabase(context, pn, mUser);                                   
3255                     }                                                                                    
3256                     // Remove all the specific components                                                
3257                     for (AppInfo a : removedApps) {                                                      
3258                         ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); 
3259                         deleteItemsFromDatabase(context, infos);                                         
3260                     }                                                                                    
3261                     removeReason = 0;                                                                    
3262                 }                                                                                        
3263                                                                                                          
3264                 // Remove any queued items from the install queue                                        
3265                 InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);     
3266                 // Call the components-removed callback                                                  
3267                 mHandler.post(new Runnable() {                                                           
3268                     public void run() {                                                                  
3269                         Callbacks cb = getCallback();                                                    
3270                         if (callbacks == cb && cb != null) {                                             
3271                             callbacks.bindComponentsRemoved(                                             
3272                                     removedPackageNames, removedApps, mUser, removeReason);              
3273                         }                                                                                
3274                     }                                                                                    
3275                 });                                                                                      
3276             }                                                                                            
3277                                                                                                          
3278             final ArrayList<Object> widgetsAndShortcuts =                                                
3279                     getSortedWidgetsAndShortcuts(context);                                               
3280             mHandler.post(new Runnable() {                                                               
3281                 @Override                                                                                
3282                 public void run() {                                                                      
3283                     Callbacks cb = getCallback();                                                        
3284                     if (callbacks == cb && cb != null) {                                                 
3285                         callbacks.bindPackagesUpdated(widgetsAndShortcuts);                              
3286                     }                                                                                    
3287                 }                                                                                        
3288             });                                                                                          
3289                                                                                                          
3290             // Write all the logs to disk                                                                
3291             mHandler.post(new Runnable() {                                                               
3292                 public void run() {                                                                      
3293                     Callbacks cb = getCallback();                                                        
3294                     if (callbacks == cb && cb != null) {                                                 
3295                         callbacks.dumpLogsToLocalData();                                                 
3296                     }                                                                                    
3297                 }                                                                                        
3298             });                                                                                          
3299         }                                                                                                
3300     }                                                                                                    
3301                                                                                                          
3302     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context) {              
3303         synchronized (sBgLock) {                                                                         
3304             if (sBgWidgetProviders != null && !sWidgetProvidersDirty) {                                  
3305                 return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());        
3306             }                                                                                            
3307             sBgWidgetProviders = new HashMap<ComponentName, LauncherAppWidgetProviderInfo>();            
3308             List<AppWidgetProviderInfo> widgets =                                                        
3309                     AppWidgetManagerCompat.getInstance(context).getAllProviders();                       
3310             LauncherAppWidgetProviderInfo info;                                                          
3311             for (AppWidgetProviderInfo pInfo : widgets) {                                                
3312                 info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                   
3313                 sBgWidgetProviders.put(info.provider, info);                                             
3314             }                                                                                            
3315                                                                                                          
3316             Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();         
3317             for (CustomAppWidget widget : customWidgets) {                                               
3318                 info = new LauncherAppWidgetProviderInfo(context, widget);                               
3319                 sBgWidgetProviders.put(info.provider, info);                                             
3320             }                                                                                            
3321             sWidgetProvidersDirty = false;                                                               
3322             return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());            
3323         }                                                                                                
3324     }                                                                                                    
3325                                                                                                          
3326     public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {       
3327         synchronized (sBgLock) {                                                                         
3328             if (sBgWidgetProviders == null) {                                                            
3329                 getWidgetProviders(ctx);                                                                 
3330             }                                                                                            
3331             return sBgWidgetProviders.get(name);                                                         
3332         }                                                                                                
3333     }                                                                                                    
3334                                                                                                          
3335     // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                     
3336     public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                      
3337         PackageManager packageManager = context.getPackageManager();                                     
3338         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3339         widgetsAndShortcuts.addAll(getWidgetProviders(context));                                         
3340         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3341         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3342         Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));             
3343         return widgetsAndShortcuts;                                                                      
3344     }                                                                                                    
3345                                                                                                          
3346     private static boolean isPackageDisabled(Context context, String packageName,                        
3347             UserHandleCompat user) {                                                                     
3348         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3349         return !launcherApps.isPackageEnabledForProfile(packageName, user);                              
3350     }                                                                                                    
3351                                                                                                          
3352     public static boolean isValidPackageActivity(Context context, ComponentName cn,                      
3353             UserHandleCompat user) {                                                                     
3354         if (cn == null) {                                                                                
3355             return false;                                                                                
3356         }                                                                                                
3357         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3358         if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                       
3359             return false;                                                                                
3360         }                                                                                                
3361         return launcherApps.isActivityEnabledForProfile(cn, user);                                       
3362     }                                                                                                    
3363                                                                                                          
3364     public static boolean isValidPackage(Context context, String packageName,                            
3365             UserHandleCompat user) {                                                                     
3366         if (packageName == null) {                                                                       
3367             return false;                                                                                
3368         }                                                                                                
3369         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3370         return launcherApps.isPackageEnabledForProfile(packageName, user);                               
3371     }                                                                                                    
3372                                                                                                          
3373     /**                                                                                                  
3374      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3375      * to a package that is not yet installed on the system.                                             
3376      */                                                                                                  
3377     public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,                
3378             int promiseType) {                                                                           
3379         final ShortcutInfo info = new ShortcutInfo();                                                    
3380         info.user = UserHandleCompat.myUserHandle();                                                     
3381         mIconCache.getTitleAndIcon(info, intent, info.user);                                             
3382                                                                                                          
3383         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                      
3384             String title = (cursor != null) ? cursor.getString(titleIndex) : null;                       
3385             if (!TextUtils.isEmpty(title)) {                                                             
3386                 info.title = title;                                                                      
3387             }                                                                                            
3388             info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                               
3389         } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                            
3390             if (TextUtils.isEmpty(info.title)) {                                                         
3391                 info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                       
3392             }                                                                                            
3393             info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                             
3394         } else {                                                                                         
3395             throw new InvalidParameterException("Invalid restoreType " + promiseType);                   
3396         }                                                                                                
3397                                                                                                          
3398         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3399                 info.title.toString(), info.user);                                                       
3400         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3401         info.promisedIntent = intent;                                                                    
3402         return info;                                                                                     
3403     }                                                                                                    
3404                                                                                                          
3405     /**                                                                                                  
3406      * Make an Intent object for a restored application or shortcut item that points                     
3407      * to the market page for the item.                                                                  
3408      */                                                                                                  
3409     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                     
3410         ComponentName componentName = intent.getComponent();                                             
3411         return getMarketIntent(componentName.getPackageName());                                          
3412     }                                                                                                    
3413                                                                                                          
3414     static Intent getMarketIntent(String packageName) {                                                  
3415         return new Intent(Intent.ACTION_VIEW)                                                            
3416             .setData(new Uri.Builder()                                                                   
3417                 .scheme("market")                                                                        
3418                 .authority("details")                                                                    
3419                 .appendQueryParameter("id", packageName)                                                 
3420                 .build());                                                                               
3421     }                                                                                                    
3422                                                                                                          
3423     /**                                                                                                  
3424      * Make an ShortcutInfo object for a shortcut that is an application.                                
3425      *                                                                                                   
3426      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3427      */                                                                                                  
3428     public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,                        
3429             UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,             
3430             boolean allowMissingTarget) {                                                                
3431         if (user == null) {                                                                              
3432             Log.d(TAG, "Null user found in getShortcutInfo");                                            
3433             return null;                                                                                 
3434         }                                                                                                
3435                                                                                                          
3436         ComponentName componentName = intent.getComponent();                                             
3437         if (componentName == null) {                                                                     
3438             Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                  
3439             return null;                                                                                 
3440         }                                                                                                
3441                                                                                                          
3442         Intent newIntent = new Intent(intent.getAction(), null);                                         
3443         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3444         newIntent.setComponent(componentName);                                                           
3445         LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                 
3446         if ((lai == null) && !allowMissingTarget) {                                                      
3447             Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                   
3448             return null;                                                                                 
3449         }                                                                                                
3450                                                                                                          
3451         final ShortcutInfo info = new ShortcutInfo();                                                    
3452         mIconCache.getTitleAndIcon(info, componentName, lai, user, false);                               
3453         if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {                     
3454             Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                             
3455             info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                         
3456         }                                                                                                
3457                                                                                                          
3458         // from the db                                                                                   
3459         if (TextUtils.isEmpty(info.title) && c != null) {                                                
3460             info.title =  c.getString(titleIndex);                                                       
3461         }                                                                                                
3462                                                                                                          
3463         // fall back to the class name of the activity                                                   
3464         if (info.title == null) {                                                                        
3465             info.title = componentName.getClassName();                                                   
3466         }                                                                                                
3467                                                                                                          
3468         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3469         info.user = user;                                                                                
3470         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3471                 info.title.toString(), info.user);                                                       
3472         return info;                                                                                     
3473     }                                                                                                    
3474                                                                                                          
3475     static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                               
3476             ItemInfoFilter f) {                                                                          
3477         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3478         for (ItemInfo i : infos) {                                                                       
3479             if (i instanceof ShortcutInfo) {                                                             
3480                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3481                 ComponentName cn = info.getTargetComponent();                                            
3482                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3483                     filtered.add(info);                                                                  
3484                 }                                                                                        
3485             } else if (i instanceof FolderInfo) {                                                        
3486                 FolderInfo info = (FolderInfo) i;                                                        
3487                 for (ShortcutInfo s : info.contents) {                                                   
3488                     ComponentName cn = s.getTargetComponent();                                           
3489                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3490                         filtered.add(s);                                                                 
3491                     }                                                                                    
3492                 }                                                                                        
3493             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3494                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3495                 ComponentName cn = info.providerName;                                                    
3496                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3497                     filtered.add(info);                                                                  
3498                 }                                                                                        
3499             }                                                                                            
3500         }                                                                                                
3501         return new ArrayList<ItemInfo>(filtered);                                                        
3502     }                                                                                                    
3503                                                                                                          
3504     private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                   
3505             final UserHandleCompat user) {                                                               
3506         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3507             @Override                                                                                    
3508             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3509                 if (info.user == null) {                                                                 
3510                     return cn.equals(cname);                                                             
3511                 } else {                                                                                 
3512                     return cn.equals(cname) && info.user.equals(user);                                   
3513                 }                                                                                        
3514             }                                                                                            
3515         };                                                                                               
3516         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3517     }                                                                                                    
3518                                                                                                          
3519     /**                                                                                                  
3520      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3521      */                                                                                                  
3522     private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                      
3523             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,               
3524             int titleIndex) {                                                                            
3525                                                                                                          
3526         Bitmap icon = null;                                                                              
3527         final ShortcutInfo info = new ShortcutInfo();                                                    
3528         // Non-app shortcuts are only supported for current user.                                        
3529         info.user = UserHandleCompat.myUserHandle();                                                     
3530         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3531                                                                                                          
3532         // TODO: If there's an explicit component and we can't install that, delete it.                  
3533                                                                                                          
3534         info.title = c.getString(titleIndex);                                                            
3535                                                                                                          
3536         int iconType = c.getInt(iconTypeIndex);                                                          
3537         switch (iconType) {                                                                              
3538         case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                              
3539             String packageName = c.getString(iconPackageIndex);                                          
3540             String resourceName = c.getString(iconResourceIndex);                                        
3541             info.customIcon = false;                                                                     
3542             // the resource                                                                              
3543             icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);           
3544             // the db                                                                                    
3545             if (icon == null) {                                                                          
3546                 icon = Utilities.createIconBitmap(c, iconIndex, context);                                
3547             }                                                                                            
3548             // the fallback icon                                                                         
3549             if (icon == null) {                                                                          
3550                 icon = mIconCache.getDefaultIcon(info.user);                                             
3551                 info.usingFallbackIcon = true;                                                           
3552             }                                                                                            
3553             break;                                                                                       
3554         case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                
3555             icon = Utilities.createIconBitmap(c, iconIndex, context);                                    
3556             if (icon == null) {                                                                          
3557                 icon = mIconCache.getDefaultIcon(info.user);                                             
3558                 info.customIcon = false;                                                                 
3559                 info.usingFallbackIcon = true;                                                           
3560             } else {                                                                                     
3561                 info.customIcon = true;                                                                  
3562             }                                                                                            
3563             break;                                                                                       
3564         default:                                                                                         
3565             icon = mIconCache.getDefaultIcon(info.user);                                                 
3566             info.usingFallbackIcon = true;                                                               
3567             info.customIcon = false;                                                                     
3568             break;                                                                                       
3569         }                                                                                                
3570         info.setIcon(icon);                                                                              
3571         return info;                                                                                     
3572     }                                                                                                    
3573                                                                                                          
3574     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                  
3575         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3576         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3577         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3578                                                                                                          
3579         if (intent == null) {                                                                            
3580             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3581             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3582             return null;                                                                                 
3583         }                                                                                                
3584                                                                                                          
3585         Bitmap icon = null;                                                                              
3586         boolean customIcon = false;                                                                      
3587         ShortcutIconResource iconResource = null;                                                        
3588                                                                                                          
3589         if (bitmap instanceof Bitmap) {                                                                  
3590             icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                 
3591             customIcon = true;                                                                           
3592         } else {                                                                                         
3593             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3594             if (extra instanceof ShortcutIconResource) {                                                 
3595                 iconResource = (ShortcutIconResource) extra;                                             
3596                 icon = Utilities.createIconBitmap(iconResource.packageName,                              
3597                         iconResource.resourceName, mIconCache, context);                                 
3598             }                                                                                            
3599         }                                                                                                
3600                                                                                                          
3601         final ShortcutInfo info = new ShortcutInfo();                                                    
3602                                                                                                          
3603         // Only support intents for current user for now. Intents sent from other                        
3604         // users wouldn't get here without intent forwarding anyway.                                     
3605         info.user = UserHandleCompat.myUserHandle();                                                     
3606         if (icon == null) {                                                                              
3607             icon = mIconCache.getDefaultIcon(info.user);                                                 
3608             info.usingFallbackIcon = true;                                                               
3609         }                                                                                                
3610         info.setIcon(icon);                                                                              
3611                                                                                                          
3612         info.title = name;                                                                               
3613         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3614                 info.title.toString(), info.user);                                                       
3615         info.intent = intent;                                                                            
3616         info.customIcon = customIcon;                                                                    
3617         info.iconResource = iconResource;                                                                
3618                                                                                                          
3619         return info;                                                                                     
3620     }                                                                                                    
3621                                                                                                          
3622     /**                                                                                                  
3623      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3624      * or make a new one.                                                                                
3625      */                                                                                                  
3626     private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {             
3627         // See if a placeholder was created for us already                                               
3628         FolderInfo folderInfo = folders.get(id);                                                         
3629         if (folderInfo == null) {                                                                        
3630             // No placeholder -- create a new instance                                                   
3631             folderInfo = new FolderInfo();                                                               
3632             folders.put(id, folderInfo);                                                                 
3633         }                                                                                                
3634         return folderInfo;                                                                               
3635     }                                                                                                    
3636                                                                                                          
3637     public static final Comparator<AppInfo> getAppNameComparator() {                                     
3638         final Collator collator = Collator.getInstance();                                                
3639         return new Comparator<AppInfo>() {                                                               
3640             public final int compare(AppInfo a, AppInfo b) {                                             
3641                 if (a.user.equals(b.user)) {                                                             
3642                     int result = collator.compare(a.title.toString().trim(),                             
3643                             b.title.toString().trim());                                                  
3644                     if (result == 0) {                                                                   
3645                         result = a.componentName.compareTo(b.componentName);                             
3646                     }                                                                                    
3647                     return result;                                                                       
3648                 } else {                                                                                 
3649                     // TODO Need to figure out rules for sorting                                         
3650                     // profiles, this puts work second.                                                  
3651                     return a.user.toString().compareTo(b.user.toString());                               
3652                 }                                                                                        
3653             }                                                                                            
3654         };                                                                                               
3655     }                                                                                                    
3656     public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                  
3657             = new Comparator<AppInfo>() {                                                                
3658         public final int compare(AppInfo a, AppInfo b) {                                                 
3659             if (a.firstInstallTime < b.firstInstallTime) return 1;                                       
3660             if (a.firstInstallTime > b.firstInstallTime) return -1;                                      
3661             return 0;                                                                                    
3662         }                                                                                                
3663     };                                                                                                   
3664     static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                             
3665         if (info.activityInfo != null) {                                                                 
3666             return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);             
3667         } else {                                                                                         
3668             return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);               
3669         }                                                                                                
3670     }                                                                                                    
3671                                                                                                          
3672     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                  
3673         private final AppWidgetManagerCompat mManager;                                                   
3674         private final PackageManager mPackageManager;                                                    
3675         private final HashMap<Object, String> mLabelCache;                                               
3676         private final Collator mCollator;                                                                
3677                                                                                                          
3678         WidgetAndShortcutNameComparator(Context context) {                                               
3679             mManager = AppWidgetManagerCompat.getInstance(context);                                      
3680             mPackageManager = context.getPackageManager();                                               
3681             mLabelCache = new HashMap<Object, String>();                                                 
3682             mCollator = Collator.getInstance();                                                          
3683         }                                                                                                
3684         public final int compare(Object a, Object b) {                                                   
3685             String labelA, labelB;                                                                       
3686             if (mLabelCache.containsKey(a)) {                                                            
3687                 labelA = mLabelCache.get(a);                                                             
3688             } else {                                                                                     
3689                 labelA = (a instanceof LauncherAppWidgetProviderInfo)                                    
3690                         ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a)                          
3691                         : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                
3692                 mLabelCache.put(a, labelA);                                                              
3693             }                                                                                            
3694             if (mLabelCache.containsKey(b)) {                                                            
3695                 labelB = mLabelCache.get(b);                                                             
3696             } else {                                                                                     
3697                 labelB = (b instanceof LauncherAppWidgetProviderInfo)                                    
3698                         ? mManager.loadLabel((LauncherAppWidgetProviderInfo) b)                          
3699                         : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                
3700                 mLabelCache.put(b, labelB);                                                              
3701             }                                                                                            
3702             return mCollator.compare(labelA, labelB);                                                    
3703         }                                                                                                
3704     }                                                                                                    
3705                                                                                                          
3706     static boolean isValidProvider(AppWidgetProviderInfo provider) {                                     
3707         return (provider != null) && (provider.provider != null)                                         
3708                 && (provider.provider.getPackageName() != null);                                         
3709     }                                                                                                    
3710                                                                                                          
3711     public void dumpState() {                                                                            
3712         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3713         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3714         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3715         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3716         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3717         if (mLoaderTask != null) {                                                                       
3718             mLoaderTask.dumpState();                                                                     
3719         } else {                                                                                         
3720             Log.d(TAG, "mLoaderTask=null");                                                              
3721         }                                                                                                
3722     }                                                                                                    
3723                                                                                                          
3724     public Callbacks getCallback() {                                                                     
3725         return mCallbacks != null ? mCallbacks.get() : null;                                             
3726     }                                                                                                    
3727 }                                                                                                        








   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16 package com.android.launcher3;                                                                           
  17                                                                                                          
  18 import android.app.SearchManager;                                                                        
  19 import android.appwidget.AppWidgetProviderInfo;                                                          
  20 import android.content.BroadcastReceiver;                                                                
  21 import android.content.ComponentName;                                                                    
  22 import android.content.ContentProviderClient;                                                            
  23 import android.content.ContentProviderOperation;                                                         
  24 import android.content.ContentResolver;                                                                  
  25 import android.content.ContentValues;                                                                    
  26 import android.content.Context;                                                                          
  27 import android.content.Intent.ShortcutIconResource;                                                      
  28 import android.content.Intent;                                                                           
  29 import android.content.IntentFilter;                                                                     
  30 import android.content.SharedPreferences;                                                                
  31 import android.content.pm.PackageManager;                                                                
  32 import android.content.pm.ProviderInfo;                                                                  
  33 import android.content.pm.ResolveInfo;                                                                   
  34 import android.content.res.Configuration;                                                                
  35 import android.content.res.Resources;                                                                    
  36 import android.database.Cursor;                                                                          
  37 import android.graphics.Bitmap;                                                                          
  38 import android.graphics.Rect;                                                                            
  39 import android.net.Uri;                                                                                  
  40 import android.os.Environment;                                                                           
  41 import android.os.Handler;                                                                               
  42 import android.os.HandlerThread;                                                                         
  43 import android.os.Parcelable;                                                                            
  44 import android.os.Process;                                                                               
  45 import android.os.RemoteException;                                                                       
  46 import android.os.SystemClock;                                                                           
  47 import android.provider.BaseColumns;                                                                     
  48 import android.text.TextUtils;                                                                           
  49 import android.util.Log;                                                                                 
  50 import android.util.LongSparseArray;                                                                     
  51 import android.util.Pair;                                                                                
  52 import com.android.launcher3.compat.AppWidgetManagerCompat;                                              
  53 import com.android.launcher3.compat.LauncherActivityInfoCompat;                                          
  54 import com.android.launcher3.compat.LauncherAppsCompat;                                                  
  55 import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                           
  56 import com.android.launcher3.compat.PackageInstallerCompat;                                              
  57 import com.android.launcher3.compat.UserHandleCompat;                                                    
  58 import com.android.launcher3.compat.UserManagerCompat;                                                   
  59 import java.lang.ref.WeakReference;                                                                      
  60 import java.net.URISyntaxException;                                                                      
  61 import java.security.InvalidParameterException;                                                          
  62 import java.text.Collator;                                                                               
  63 import java.util.ArrayList;                                                                              
  64 import java.util.Arrays;                                                                                 
  65 import java.util.Collection;                                                                             
  66 import java.util.Collections;                                                                            
  67 import java.util.Comparator;                                                                             
  68 import java.util.HashMap;                                                                                
  69 import java.util.HashSet;                                                                                
  70 import java.util.Iterator;                                                                               
  71 import java.util.List;                                                                                   
  72 import java.util.Map.Entry;                                                                              
  73 import java.util.Set;                                                                                    
  74                                                                                                          
  75                                                                                                          
  76 /**                                                                                                      
  77  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  78  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  79  * for the Launcher.                                                                                     
  80  */                                                                                                      
  81 public class LauncherModel extends BroadcastReceiver implements LauncherAppsCompat.OnAppsChangedCallbackC🔵
  82     static final boolean DEBUG_LOADERS = false;                                                          
  83                                                                                                          
  84     private static final boolean DEBUG_RECEIVER = false;                                                 
  85                                                                                                          
  86     private static final boolean REMOVE_UNRESTORED_ICONS = true;                                         
  87                                                                                                          
  88     private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                  
  89                                                                                                          
  90     static final String TAG = "Launcher.Model";                                                          
  91                                                                                                          
  92     public static final int LOADER_FLAG_NONE = 0;                                                        
  93                                                                                                          
  94     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  95                                                                                                          
  96     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  97                                                                                                          
  98     // batch size for the workspace icons                                                                
  99     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
 100                                                                                                          
 101     private static final long INVALID_SCREEN_ID = -1L;                                                   
 102                                                                                                          
 103     private final boolean mAppsCanBeOnRemoveableStorage;                                                 
 104                                                                                                          
 105     private final boolean mOldContentProviderExists;                                                     
 106                                                                                                          
 107     private final LauncherAppState mApp;                                                                 
 108                                                                                                          
 109     private final Object mLock = new Object();                                                           
 110                                                                                                          
 111     private DeferredHandler mHandler = new DeferredHandler();                                            
 112                                                                                                          
 113     private LoaderTask mLoaderTask;                                                                      
 114                                                                                                          
 115     private boolean mIsLoaderTaskRunning;                                                                
 116                                                                                                          
 117     /**                                                                                                  
 118      * Maintain a set of packages per user, for which we added a shortcut on the workspace.              
 119      */                                                                                                  
 120     private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";    
 121                                                                                                          
 122     // Specific runnable types that are run on the main thread deferred handler, this allows us to       
 123     // clear all queued binding runnables when the Launcher activity is destroyed.                       
 124     private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                            
 125                                                                                                          
 126     private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                           
 127                                                                                                          
 128     private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                    
 129                                                                                                          
 130     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");             
 131                                                                                                          
 132     static {                                                                                             
 133         sWorkerThread.start();                                                                           
 134     }                                                                                                    
 135                                                                                                          
 136     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                       
 137                                                                                                          
 138     // We start off with everything not loaded.  After that, we assume that                              
 139     // our monitoring of the package manager provides all updates and we never                           
 140     // need to do a requery.  These are only ever touched from the loader thread.                        
 141     private boolean mWorkspaceLoaded;                                                                    
 142                                                                                                          
 143     private boolean mAllAppsLoaded;                                                                      
 144                                                                                                          
 145     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 146     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 147     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 148     // a normal load, we also clear this set of Runnables.                                               
 149     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 150                                                                                                          
 151     private WeakReference<Callbacks> mCallbacks;                                                         
 152                                                                                                          
 153     // < only access in worker thread >                                                                  
 154     // < only access in worker thread >                                                                  
 155     AllAppsList mBgAllAppsList;                                                                          
 156                                                                                                          
 157     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 158     // other locks, this one can generally be held long-term because we never expect any of these        
 159     // static data structures to be referenced outside of the worker thread except on the first          
 160     // load after configuration change.                                                                  
 161     static final Object sBgLock = new Object();                                                          
 162                                                                                                          
 163     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 164     // LauncherModel to their ids                                                                        
 165     static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                  
 166                                                                                                          
 167     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 168     // created by LauncherModel that are directly on the home screen (however, no widgets or             
 169     // shortcuts within folders).                                                                        
 170     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 171                                                                                                          
 172     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 173     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 174     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 175         new ArrayList<LauncherAppWidgetInfo>();                                                          
 176                                                                                                          
 177     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 178     static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                 
 179                                                                                                          
 180     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 181     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 182     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 183                                                                                                          
 184     // sBgWidgetProviders is the set of widget providers including custom internal widgets               
 185     public static HashMap<ComponentName, LauncherAppWidgetProviderInfo> sBgWidgetProviders;              
 186                                                                                                          
 187     public static boolean sWidgetProvidersDirty;                                                         
 188                                                                                                          
 189     // sPendingPackages is a set of packages which could be on sdcard and are not available yet          
 190     static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages = new HashMap<UserHandleComp🔵
 191                                                                                                          
 192     // </ only access in worker thread >                                                                 
 193     // </ only access in worker thread >                                                                 
 194                                                                                                          
 195     private IconCache mIconCache;                                                                        
 196                                                                                                          
 197     protected int mPreviousConfigMcc;                                                                    
 198                                                                                                          
 199     private final LauncherAppsCompat mLauncherApps;                                                      
 200                                                                                                          
 201     private final UserManagerCompat mUserManager;                                                        
 202                                                                                                          
 203     public interface Callbacks {                                                                         
 204         public abstract boolean setLoadOnResume();                                                       
 205                                                                                                          
 206         public abstract int getCurrentWorkspaceScreen();                                                 
 207                                                                                                          
 208         public abstract void startBinding();                                                             
 209                                                                                                          
 210         public abstract void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end, boolean forceAn🔵
 211                                                                                                          
 212         public abstract void bindScreens(ArrayList<Long> orderedScreenIds);                              
 213                                                                                                          
 214         public abstract void bindAddScreens(ArrayList<Long> orderedScreenIds);                           
 215                                                                                                          
 216         public abstract void bindFolders(HashMap<Long, FolderInfo> folders);                             
 217                                                                                                          
 218         public abstract void finishBindingItems();                                                       
 219                                                                                                          
 220         public abstract void bindAppWidget(LauncherAppWidgetInfo info);                                  
 221                                                                                                          
 222         public abstract void bindAllApplications(ArrayList<AppInfo> apps);                               
 223                                                                                                          
 224         public abstract void bindAppsAdded(ArrayList<Long> newScreens, ArrayList<ItemInfo> addNotAnimated🔵
 225                                                                                                          
 226         public abstract void bindAppsUpdated(ArrayList<AppInfo> apps);                                   
 227                                                                                                          
 228         public abstract void bindShortcutsChanged(ArrayList<ShortcutInfo> updated, ArrayList<ShortcutInfo🔵
 229                                                                                                          
 230         public abstract void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);              
 231                                                                                                          
 232         public abstract void updatePackageState(ArrayList<PackageInstallInfo> installInfo);              
 233                                                                                                          
 234         public abstract void updatePackageBadge(String packageName);                                     
 235                                                                                                          
 236         public abstract void bindComponentsRemoved(ArrayList<String> packageNames, ArrayList<AppInfo> app🔵
 237                                                                                                          
 238         public abstract void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                 
 239                                                                                                          
 240         public abstract void bindSearchablesChanged();                                                   
 241                                                                                                          
 242         public abstract boolean isAllAppsButtonRank(int rank);                                           
 243                                                                                                          
 244         public abstract void onPageBoundSynchronously(int page);                                         
 245                                                                                                          
 246         public abstract void dumpLogsToLocalData();                                                      
 247                                                                                                          
 248         public abstract void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId, i🔵
 249     }                                                                                                    
 250                                                                                                          
 251     public interface ItemInfoFilter {                                                                    
 252         public abstract boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);            
 253     }                                                                                                    
 254                                                                                                          
 255     public interface ScreenPosProvider {                                                                 
 256         public abstract int getScreenIndex(ArrayList<Long> screenIDs);                                   
 257     }                                                                                                    
 258                                                                                                          
 259     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 260         Context context = app.getContext();                                                              
 261         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 262         String oldProvider = context.getString(R.string.old_launcher_provider_uri);                      
 263         // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different               
 264         // resource string.                                                                              
 265         String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                
 266         ProviderInfo providerInfo = context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY,🔵
 267         ProviderInfo redirectProvider = context.getPackageManager().resolveContentProvider(redirectAuthor🔵
 268         Log.d(TAG, "Old launcher provider: " + oldProvider);                                             
 269         mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                
 270         if (mOldContentProviderExists) {                                                                 
 271             Log.d(TAG, "Old launcher provider exists.");                                                 
 272         } else {                                                                                         
 273             Log.d(TAG, "Old launcher provider does not exist.");                                         
 274         }                                                                                                
 275         mApp = app;                                                                                      
 276         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 277         mIconCache = iconCache;                                                                          
 278         final Resources res = context.getResources();                                                    
 279         Configuration config = res.getConfiguration();                                                   
 280         mPreviousConfigMcc = config.mcc;                                                                 
 281         mLauncherApps = LauncherAppsCompat.getInstance(context);                                         
 282         mUserManager = UserManagerCompat.getInstance(context);                                           
 283     }                                                                                                    
 284                                                                                                          
 285     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 286      * posted on the main thread handler. */                                                             
 287     private void runOnMainThread(Runnable r) {                                                           
 288         runOnMainThread(r, 0);                                                                           
 289     }                                                                                                    
 290                                                                                                          
 291     private void runOnMainThread(Runnable r, int type) {                                                 
 292         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 293             // If we are on the worker thread, post onto the main handler                                
 294             mHandler.post(r);                                                                            
 295         } else {                                                                                         
 296             r.run();                                                                                     
 297         }                                                                                                
 298     }                                                                                                    
 299                                                                                                          
 300     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 301      * posted on the worker thread handler. */                                                           
 302     private static void runOnWorkerThread(Runnable r) {                                                  
 303         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 304             r.run();                                                                                     
 305         } else {                                                                                         
 306             // If we are not on the worker thread, then post to the worker handler                       
 307             sWorker.post(r);                                                                             
 308         }                                                                                                
 309     }                                                                                                    
 310                                                                                                          
 311     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 312         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 313     }                                                                                                    
 314                                                                                                          
 315     public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                       
 316         // Process the updated package state                                                             
 317         Runnable r = new Runnable() {                                                                    
 318             public void run() {                                                                          
 319                 Callbacks callbacks = getCallback();                                                     
 320                 if (callbacks != null) {                                                                 
 321                     callbacks.updatePackageState(installInfo);                                           
 322                 }                                                                                        
 323             }                                                                                            
 324         };                                                                                               
 325         mHandler.post(r);                                                                                
 326     }                                                                                                    
 327                                                                                                          
 328     public void updatePackageBadge(final String packageName) {                                           
 329         // Process the updated package badge                                                             
 330         Runnable r = new Runnable() {                                                                    
 331             public void run() {                                                                          
 332                 Callbacks callbacks = getCallback();                                                     
 333                 if (callbacks != null) {                                                                 
 334                     callbacks.updatePackageBadge(packageName);                                           
 335                 }                                                                                        
 336             }                                                                                            
 337         };                                                                                               
 338         mHandler.post(r);                                                                                
 339     }                                                                                                    
 340                                                                                                          
 341     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 342         final Callbacks callbacks = getCallback();                                                       
 343                                                                                                          
 344         if (allAppsApps == null) {                                                                       
 345             throw new RuntimeException("allAppsApps must not be null");                                  
 346         }                                                                                                
 347         if (allAppsApps.isEmpty()) {                                                                     
 348             return;                                                                                      
 349         }                                                                                                
 350                                                                                                          
 351         // Process the newly added applications and add them to the database first                       
 352         Runnable r = new Runnable() {                                                                    
 353             public void run() {                                                                          
 354                 runOnMainThread(new Runnable() {                                                         
 355                     public void run() {                                                                  
 356                         Callbacks cb = getCallback();                                                    
 357                         if (callbacks == cb && cb != null) {                                             
 358                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 359                         }                                                                                
 360                     }                                                                                    
 361                 });                                                                                      
 362             }                                                                                            
 363         };                                                                                               
 364         runOnWorkerThread(r);                                                                            
 365     }                                                                                                    
 366                                                                                                          
 367     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 368             final ArrayList<ItemInfo> workspaceApps) {                                                   
 369         addAndBindAddedWorkspaceApps(context, workspaceApps,                                             
 370                 new ScreenPosProvider() {                                                                
 371                                                                                                          
 372                     @Override                                                                            
 373                     public int getScreenIndex(ArrayList<Long> screenIDs) {                               
 374                         return screenIDs.isEmpty() ? 0 : 1;                                              
 375                     }                                                                                    
 376                 }, 1, false);                                                                            
 377     }                                                                                                    
 378                                                                                                          
 379     private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,               
 380             int[] xy, int spanX, int spanY) {                                                            
 381         LauncherAppState app = LauncherAppState.getInstance();                                           
 382         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 383         final int xCount = (int) grid.numColumns;                                                        
 384         final int yCount = (int) grid.numRows;                                                           
 385         boolean[][] occupied = new boolean[xCount][yCount];                                              
 386         if (occupiedPos != null) {                                                                       
 387             for (Rect r : occupiedPos) {                                                                 
 388                 for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                         
 389                     for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                     
 390                         occupied[x][y] = true;                                                           
 391                     }                                                                                    
 392                 }                                                                                        
 393             }                                                                                            
 394         }                                                                                                
 395         return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                    
 396     }                                                                                                    
 397                                                                                                          
 398     /**                                                                                                  
 399      * Find a position on the screen for the given size or adds a new screen.                            
 400      * @return screenId and the coordinates for the item.                                                
 401      */                                                                                                  
 402     private static Pair<Long, int[]> findSpaceForItem(                                                   
 403             Context context,                                                                             
 404             ScreenPosProvider preferredScreen,                                                           
 405             int fallbackStartScreen,                                                                     
 406             ArrayList<Long> workspaceScreens,                                                            
 407             ArrayList<Long> addedWorkspaceScreensFinal,                                                  
 408             int spanX, int spanY) {                                                                      
 409         // Load position of items which are on the desktop. We can't use sBgItemsIdMap because           
 410         // loadWorkspace() may not have been called.                                                     
 411         final ContentResolver cr = context.getContentResolver();                                         
 412         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 413                 new String[] {                                                                           
 414                     LauncherSettings.Favorites.SCREEN,                                                   
 415                     LauncherSettings.Favorites.CELLX,                                                    
 416                     LauncherSettings.Favorites.CELLY,                                                    
 417                     LauncherSettings.Favorites.SPANX,                                                    
 418                     LauncherSettings.Favorites.SPANY,                                                    
 419                     LauncherSettings.Favorites.CONTAINER                                                 
 420                  },                                                                                      
 421                  "container=?",                                                                          
 422                  new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },        
 423                  null);                                                                                  
 424                                                                                                          
 425         final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);              
 426         final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                
 427         final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                
 428         final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                
 429         final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                
 430         LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();           
 431         try {                                                                                            
 432             while (c.moveToNext()) {                                                                     
 433                 Rect rect = new Rect();                                                                  
 434                 rect.left = c.getInt(cellXIndex);                                                        
 435                 rect.top = c.getInt(cellYIndex);                                                         
 436                 rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                              
 437                 rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                              
 438                                                                                                          
 439                 long screenId = c.getInt(screenIndex);                                                   
 440                 ArrayList<Rect> items = screenItems.get(screenId);                                       
 441                 if (items == null) {                                                                     
 442                     items = new ArrayList<Rect>();                                                       
 443                     screenItems.put(screenId, items);                                                    
 444                 }                                                                                        
 445                 items.add(rect);                                                                         
 446             }                                                                                            
 447         } catch (Exception e) {                                                                          
 448             screenItems.clear();                                                                         
 449         } finally {                                                                                      
 450             c.close();                                                                                   
 451         }                                                                                                
 452                                                                                                          
 453         // Find appropriate space for the item.                                                          
 454         long screenId = 0;                                                                               
 455         int[] cordinates = new int[2];                                                                   
 456         boolean found = false;                                                                           
 457                                                                                                          
 458         int screenCount = workspaceScreens.size();                                                       
 459         // First check the preferred screen.                                                             
 460         int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                     
 461         if (preferredScreenIndex < screenCount) {                                                        
 462             screenId = workspaceScreens.get(preferredScreenIndex);                                       
 463             found = findNextAvailableIconSpaceInScreen(                                                  
 464                     screenItems.get(screenId), cordinates, spanX, spanY);                                
 465         }                                                                                                
 466                                                                                                          
 467         if (!found) {                                                                                    
 468             // Search on any of the screens.                                                             
 469             for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                     
 470                 screenId = workspaceScreens.get(screen);                                                 
 471                 if (findNextAvailableIconSpaceInScreen(                                                  
 472                         screenItems.get(screenId), cordinates, spanX, spanY)) {                          
 473                     // We found a space for it                                                           
 474                     found = true;                                                                        
 475                     break;                                                                               
 476                 }                                                                                        
 477             }                                                                                            
 478         }                                                                                                
 479                                                                                                          
 480         if (!found) {                                                                                    
 481             // Still no position found. Add a new screen to the end.                                     
 482             screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                     
 483                                                                                                          
 484             // Save the screen id for binding in the workspace                                           
 485             workspaceScreens.add(screenId);                                                              
 486             addedWorkspaceScreensFinal.add(screenId);                                                    
 487                                                                                                          
 488             // If we still can't find an empty space, then God help us all!!!                            
 489             if (!findNextAvailableIconSpaceInScreen(                                                     
 490                     screenItems.get(screenId), cordinates, spanX, spanY)) {                              
 491                 throw new RuntimeException("Can't find space to add the item");                          
 492             }                                                                                            
 493         }                                                                                                
 494         return Pair.create(screenId, cordinates);                                                        
 495     }                                                                                                    
 496                                                                                                          
 497     /**                                                                                                  
 498      * Adds the provided items to the workspace.                                                         
 499      * @param preferredScreen the screen where we should try to add the app first                        
 500      * @param fallbackStartScreen the screen to start search for empty space if                          
 501      * preferredScreen is not available.                                                                 
 502      */                                                                                                  
 503     public void addAndBindPendingItem(                                                                   
 504             final Context context,                                                                       
 505             final PendingAddItemInfo addInfo,                                                            
 506             final ScreenPosProvider preferredScreen,                                                     
 507             final int fallbackStartScreen) {                                                             
 508         final Callbacks callbacks = getCallback();                                                       
 509         // Process the newly added applications and add them to the database first                       
 510         Runnable r = new Runnable() {                                                                    
 511             public void run() {                                                                          
 512                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 513                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 514                                                                                                          
 515                 // Find appropriate space for the item.                                                  
 516                 Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                    
 517                         fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,               
 518                         addInfo.spanX,                                                                   
 519                         addInfo.spanY);                                                                  
 520                 final long screenId = coords.first;                                                      
 521                 final int[] cordinates = coords.second;                                                  
 522                                                                                                          
 523                 // Update the workspace screens                                                          
 524                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 525                 runOnMainThread(new Runnable() {                                                         
 526                     public void run() {                                                                  
 527                         Callbacks cb = getCallback();                                                    
 528                         if (callbacks == cb && cb != null) {                                             
 529                             cb.bindAddScreens(addedWorkspaceScreensFinal);                               
 530                             cb.bindAddPendingItem(addInfo,                                               
 531                                     LauncherSettings.Favorites.CONTAINER_DESKTOP,                        
 532                                     screenId, cordinates, addInfo.spanX, addInfo.spanY);                 
 533                         }                                                                                
 534                     }                                                                                    
 535                 });                                                                                      
 536             }                                                                                            
 537         };                                                                                               
 538         runOnWorkerThread(r);                                                                            
 539     }                                                                                                    
 540                                                                                                          
 541     /**                                                                                                  
 542      * Adds the provided items to the workspace.                                                         
 543      * @param preferredScreen the screen where we should try to add the app first                        
 544      * @param fallbackStartScreen the screen to start search for empty space if                          
 545      * preferredScreen is not available.                                                                 
 546      */                                                                                                  
 547     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 548             final ArrayList<ItemInfo> workspaceApps,                                                     
 549             final ScreenPosProvider preferredScreen,                                                     
 550             final int fallbackStartScreen,                                                               
 551             final boolean allowDuplicate) {                                                              
 552         final Callbacks callbacks = getCallback();                                                       
 553         if (workspaceApps.isEmpty()) {                                                                   
 554             return;                                                                                      
 555         }                                                                                                
 556         // Process the newly added applications and add them to the database first                       
 557         Runnable r = new Runnable() {                                                                    
 558             public void run() {                                                                          
 559                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 560                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 561                                                                                                          
 562                 // Get the list of workspace screens.  We need to append to this list and                
 563                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 564                 // called.                                                                               
 565                 ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                      
 566                 synchronized(sBgLock) {                                                                  
 567                     for (ItemInfo item : workspaceApps) {                                                
 568                         if (!allowDuplicate) {                                                           
 569                             // Short-circuit this logic if the icon exists somewhere on the workspace    
 570                             if (shortcutExists(context, item.title.toString(),                           
 571                                     item.getIntent(), item.user)) {                                      
 572                                 continue;                                                                
 573                             }                                                                            
 574                         }                                                                                
 575                                                                                                          
 576                         // Find appropriate space for the item.                                          
 577                         Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,            
 578                                 fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,       
 579                                 1, 1);                                                                   
 580                         long screenId = coords.first;                                                    
 581                         int[] cordinates = coords.second;                                                
 582                                                                                                          
 583                         ShortcutInfo shortcutInfo;                                                       
 584                         if (item instanceof ShortcutInfo) {                                              
 585                             shortcutInfo = (ShortcutInfo) item;                                          
 586                         } else if (item instanceof AppInfo) {                                            
 587                             shortcutInfo = ((AppInfo) item).makeShortcut();                              
 588                         } else {                                                                         
 589                             throw new RuntimeException("Unexpected info type");                          
 590                         }                                                                                
 591                                                                                                          
 592                         // Add the shortcut to the db                                                    
 593                         addItemToDatabase(context, shortcutInfo,                                         
 594                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 595                                 screenId, cordinates[0], cordinates[1], false);                          
 596                         // Save the ShortcutInfo for binding in the workspace                            
 597                         addedShortcutsFinal.add(shortcutInfo);                                           
 598                     }                                                                                    
 599                 }                                                                                        
 600                                                                                                          
 601                 // Update the workspace screens                                                          
 602                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 603                                                                                                          
 604                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 605                     runOnMainThread(new Runnable() {                                                     
 606                         public void run() {                                                              
 607                             Callbacks cb = getCallback();                                                
 608                             if (callbacks == cb && cb != null) {                                         
 609                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 610                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 611                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 612                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 613                                     long lastScreenId = info.screenId;                                   
 614                                     for (ItemInfo i : addedShortcutsFinal) {                             
 615                                         if (i.screenId == lastScreenId) {                                
 616                                             addAnimated.add(i);                                          
 617                                         } else {                                                         
 618                                             addNotAnimated.add(i);                                       
 619                                         }                                                                
 620                                     }                                                                    
 621                                 }                                                                        
 622                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 623                                         addNotAnimated, addAnimated, null);                              
 624                             }                                                                            
 625                         }                                                                                
 626                     });                                                                                  
 627                 }                                                                                        
 628             }                                                                                            
 629         };                                                                                               
 630         runOnWorkerThread(r);                                                                            
 631     }                                                                                                    
 632                                                                                                          
 633     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 634         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 635             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 636                     "main thread");                                                                      
 637         }                                                                                                
 638                                                                                                          
 639         // Clear any deferred bind runnables                                                             
 640         synchronized (mDeferredBindRunnables) {                                                          
 641             mDeferredBindRunnables.clear();                                                              
 642         }                                                                                                
 643         // Remove any queued bind runnables                                                              
 644         mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                 
 645         // Unbind all the workspace items                                                                
 646         unbindWorkspaceItemsOnMainThread();                                                              
 647     }                                                                                                    
 648                                                                                                          
 649     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 650     void unbindWorkspaceItemsOnMainThread() {                                                            
 651         // Ensure that we don't use the same workspace items data structure on the main thread           
 652         // by making a copy of workspace items first.                                                    
 653         final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                         
 654         final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                             
 655         synchronized (sBgLock) {                                                                         
 656             tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                 
 657             tmpAppWidgets.addAll(sBgAppWidgets);                                                         
 658         }                                                                                                
 659         Runnable r = new Runnable() {                                                                    
 660                 @Override                                                                                
 661                 public void run() {                                                                      
 662                    for (ItemInfo item : tmpWorkspaceItems) {                                             
 663                        item.unbind();                                                                    
 664                    }                                                                                     
 665                    for (ItemInfo item : tmpAppWidgets) {                                                 
 666                        item.unbind();                                                                    
 667                    }                                                                                     
 668                 }                                                                                        
 669             };                                                                                           
 670         runOnMainThread(r);                                                                              
 671     }                                                                                                    
 672                                                                                                          
 673     /**                                                                                                  
 674      * Adds an item to the DB if it was not created previously, or move it to a new                      
 675      * <container, screen, cellX, cellY>                                                                 
 676      */                                                                                                  
 677     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 678             long screenId, int cellX, int cellY) {                                                       
 679         if (item.container == ItemInfo.NO_ID) {                                                          
 680             // From all apps                                                                             
 681             addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                  
 682         } else {                                                                                         
 683             // From somewhere else                                                                       
 684             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 685         }                                                                                                
 686     }                                                                                                    
 687                                                                                                          
 688     static void checkItemInfoLocked(                                                                     
 689             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 690         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 691         if (modelItem != null && item != modelItem) {                                                    
 692             // check all the data is consistent                                                          
 693             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 694                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 695                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 696                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 697                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 698                         modelShortcut.id == shortcut.id &&                                               
 699                         modelShortcut.itemType == shortcut.itemType &&                                   
 700                         modelShortcut.container == shortcut.container &&                                 
 701                         modelShortcut.screenId == shortcut.screenId &&                                   
 702                         modelShortcut.cellX == shortcut.cellX &&                                         
 703                         modelShortcut.cellY == shortcut.cellY &&                                         
 704                         modelShortcut.spanX == shortcut.spanX &&                                         
 705                         modelShortcut.spanY == shortcut.spanY &&                                         
 706                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 707                         (modelShortcut.dropPos != null &&                                                
 708                                 shortcut.dropPos != null &&                                              
 709                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 710                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 711                     // For all intents and purposes, this is the same object                             
 712                     return;                                                                              
 713                 }                                                                                        
 714             }                                                                                            
 715                                                                                                          
 716             // the modelItem needs to match up perfectly with item if our model is                       
 717             // to be consistent with the database-- for now, just require                                
 718             // modelItem == item or the equality check above                                             
 719             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 720                     "modelItem: " +                                                                      
 721                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 722                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 723             RuntimeException e = new RuntimeException(msg);                                              
 724             if (stackTrace != null) {                                                                    
 725                 e.setStackTrace(stackTrace);                                                             
 726             }                                                                                            
 727             throw e;                                                                                     
 728         }                                                                                                
 729     }                                                                                                    
 730                                                                                                          
 731     static void checkItemInfo(final ItemInfo item) {                                                     
 732         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 733         final long itemId = item.id;                                                                     
 734         Runnable r = new Runnable() {                                                                    
 735             public void run() {                                                                          
 736                 synchronized (sBgLock) {                                                                 
 737                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 738                 }                                                                                        
 739             }                                                                                            
 740         };                                                                                               
 741         runOnWorkerThread(r);                                                                            
 742     }                                                                                                    
 743                                                                                                          
 744     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 745             final ItemInfo item, final String callingFunction) {                                         
 746         final long itemId = item.id;                                                                     
 747         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                         
 748         final ContentResolver cr = context.getContentResolver();                                         
 749                                                                                                          
 750         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 751         Runnable r = new Runnable() {                                                                    
 752             public void run() {                                                                          
 753                 cr.update(uri, values, null, null);                                                      
 754                 updateItemArrays(item, itemId, stackTrace);                                              
 755             }                                                                                            
 756         };                                                                                               
 757         runOnWorkerThread(r);                                                                            
 758     }                                                                                                    
 759                                                                                                          
 760     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 761             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 762         final ContentResolver cr = context.getContentResolver();                                         
 763                                                                                                          
 764         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 765         Runnable r = new Runnable() {                                                                    
 766             public void run() {                                                                          
 767                 ArrayList<ContentProviderOperation> ops =                                                
 768                         new ArrayList<ContentProviderOperation>();                                       
 769                 int count = items.size();                                                                
 770                 for (int i = 0; i < count; i++) {                                                        
 771                     ItemInfo item = items.get(i);                                                        
 772                     final long itemId = item.id;                                                         
 773                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);             
 774                     ContentValues values = valuesList.get(i);                                            
 775                                                                                                          
 776                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 777                     updateItemArrays(item, itemId, stackTrace);                                          
 778                                                                                                          
 779                 }                                                                                        
 780                 try {                                                                                    
 781                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 782                 } catch (Exception e) {                                                                  
 783                     e.printStackTrace();                                                                 
 784                 }                                                                                        
 785             }                                                                                            
 786         };                                                                                               
 787         runOnWorkerThread(r);                                                                            
 788     }                                                                                                    
 789                                                                                                          
 790     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 791         // Lock on mBgLock *after* the db operation                                                      
 792         synchronized (sBgLock) {                                                                         
 793             checkItemInfoLocked(itemId, item, stackTrace);                                               
 794                                                                                                          
 795             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 796                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 797                 // Item is in a folder, make sure this folder exists                                     
 798                 if (!sBgFolders.containsKey(item.container)) {                                           
 799                     // An items container is being set to a that of an item which is not in              
 800                     // the list of Folders.                                                              
 801                     String msg = "item: " + item + " container being set to: " +                         
 802                             item.container + ", not in the list of folders";                             
 803                     Log.e(TAG, msg);                                                                     
 804                 }                                                                                        
 805             }                                                                                            
 806                                                                                                          
 807             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 808             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 809             // that are on the desktop, as appropriate                                                   
 810             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 811             if (modelItem != null &&                                                                     
 812                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 813                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 814                 switch (modelItem.itemType) {                                                            
 815                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 816                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 817                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 818                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 819                             sBgWorkspaceItems.add(modelItem);                                            
 820                         }                                                                                
 821                         break;                                                                           
 822                     default:                                                                             
 823                         break;                                                                           
 824                 }                                                                                        
 825             } else {                                                                                     
 826                 sBgWorkspaceItems.remove(modelItem);                                                     
 827             }                                                                                            
 828         }                                                                                                
 829     }                                                                                                    
 830                                                                                                          
 831     /**                                                                                                  
 832      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 833      */                                                                                                  
 834     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,           
 835             final long screenId, final int cellX, final int cellY) {                                     
 836         item.container = container;                                                                      
 837         item.cellX = cellX;                                                                              
 838         item.cellY = cellY;                                                                              
 839                                                                                                          
 840         // We store hotseat items in canonical form which is this orientation invariant position         
 841         // in the hotseat                                                                                
 842         if (context instanceof Launcher && screenId < 0 &&                                               
 843                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 844             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 845         } else {                                                                                         
 846             item.screenId = screenId;                                                                    
 847         }                                                                                                
 848                                                                                                          
 849         final ContentValues values = new ContentValues();                                                
 850         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 851         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 852         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 853         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 854         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 855                                                                                                          
 856         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 857     }                                                                                                    
 858                                                                                                          
 859     /**                                                                                                  
 860      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 861      * cellX, cellY have already been updated on the ItemInfos.                                          
 862      */                                                                                                  
 863     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 864             final long container, final int screen) {                                                    
 865                                                                                                          
 866         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 867         int count = items.size();                                                                        
 868                                                                                                          
 869         for (int i = 0; i < count; i++) {                                                                
 870             ItemInfo item = items.get(i);                                                                
 871             item.container = container;                                                                  
 872                                                                                                          
 873             // We store hotseat items in canonical form which is this orientation invariant position     
 874             // in the hotseat                                                                            
 875             if (context instanceof Launcher && screen < 0 &&                                             
 876                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 877                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 878                         item.cellY);                                                                     
 879             } else {                                                                                     
 880                 item.screenId = screen;                                                                  
 881             }                                                                                            
 882                                                                                                          
 883             final ContentValues values = new ContentValues();                                            
 884             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 885             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 886             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 887             values.put(LauncherSettings.Favorites.RANK, item.rank);                                      
 888             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 889                                                                                                          
 890             contentValues.add(values);                                                                   
 891         }                                                                                                
 892         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 893     }                                                                                                    
 894                                                                                                          
 895     /**                                                                                                  
 896      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 897      */                                                                                                  
 898     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 899             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 900         item.container = container;                                                                      
 901         item.cellX = cellX;                                                                              
 902         item.cellY = cellY;                                                                              
 903         item.spanX = spanX;                                                                              
 904         item.spanY = spanY;                                                                              
 905                                                                                                          
 906         // We store hotseat items in canonical form which is this orientation invariant position         
 907         // in the hotseat                                                                                
 908         if (context instanceof Launcher && screenId < 0 &&                                               
 909                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 910             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 911         } else {                                                                                         
 912             item.screenId = screenId;                                                                    
 913         }                                                                                                
 914                                                                                                          
 915         final ContentValues values = new ContentValues();                                                
 916         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 917         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 918         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 919         values.put(LauncherSettings.Favorites.RANK, item.rank);                                          
 920         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 921         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 922         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 923                                                                                                          
 924         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 925     }                                                                                                    
 926                                                                                                          
 927     /**                                                                                                  
 928      * Update an item to the database in a specified container.                                          
 929      */                                                                                                  
 930     static void updateItemInDatabase(Context context, final ItemInfo item) {                             
 931         final ContentValues values = new ContentValues();                                                
 932         item.onAddToDatabase(context, values);                                                           
 933         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 934     }                                                                                                    
 935                                                                                                          
 936     /**                                                                                                  
 937      * Returns true if the shortcuts already exists in the database.                                     
 938      * we identify a shortcut by its title and intent.                                                   
 939      */                                                                                                  
 940     static boolean shortcutExists(Context context, String title, Intent intent,                          
 941             UserHandleCompat user) {                                                                     
 942         final ContentResolver cr = context.getContentResolver();                                         
 943         final Intent intentWithPkg, intentWithoutPkg;                                                    
 944                                                                                                          
 945         if (intent.getComponent() != null) {                                                             
 946             // If component is not null, an intent with null package will produce                        
 947             // the same result and should also be a match.                                               
 948             if (intent.getPackage() != null) {                                                           
 949                 intentWithPkg = intent;                                                                  
 950                 intentWithoutPkg = new Intent(intent).setPackage(null);                                  
 951             } else {                                                                                     
 952                 intentWithPkg = new Intent(intent).setPackage(                                           
 953                         intent.getComponent().getPackageName());                                         
 954                 intentWithoutPkg = intent;                                                               
 955             }                                                                                            
 956         } else {                                                                                         
 957             intentWithPkg = intent;                                                                      
 958             intentWithoutPkg = intent;                                                                   
 959         }                                                                                                
 960         String userSerial = Long.toString(UserManagerCompat.getInstance(context)                         
 961                 .getSerialNumberForUser(user));                                                          
 962         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 963             new String[] { "title", "intent", "profileId" },                                             
 964             "title=? and (intent=? or intent=?) and profileId=?",                                        
 965             new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },       
 966             null);                                                                                       
 967         try {                                                                                            
 968             return c.moveToFirst();                                                                      
 969         } finally {                                                                                      
 970             c.close();                                                                                   
 971         }                                                                                                
 972     }                                                                                                    
 973                                                                                                          
 974     /**                                                                                                  
 975      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 976      */                                                                                                  
 977     FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {            
 978         final ContentResolver cr = context.getContentResolver();                                         
 979         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 980                 "_id=? and (itemType=? or itemType=?)",                                                  
 981                 new String[] { String.valueOf(id),                                                       
 982                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 983                                                                                                          
 984         try {                                                                                            
 985             if (c.moveToFirst()) {                                                                       
 986                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 987                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 988                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 989                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 990                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 991                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 992                                                                                                          
 993                 FolderInfo folderInfo = null;                                                            
 994                 switch (c.getInt(itemTypeIndex)) {                                                       
 995                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 996                         folderInfo = findOrMakeFolder(folderList, id);                                   
 997                         break;                                                                           
 998                 }                                                                                        
 999                                                                                                          
1000                 folderInfo.title = c.getString(titleIndex);                                              
1001                 folderInfo.id = id;                                                                      
1002                 folderInfo.container = c.getInt(containerIndex);                                         
1003                 folderInfo.screenId = c.getInt(screenIndex);                                             
1004                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
1005                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
1006                                                                                                          
1007                 return folderInfo;                                                                       
1008             }                                                                                            
1009         } finally {                                                                                      
1010             c.close();                                                                                   
1011         }                                                                                                
1012                                                                                                          
1013         return null;                                                                                     
1014     }                                                                                                    
1015                                                                                                          
1016     /**                                                                                                  
1017      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
1018      * cellY fields of the item. Also assigns an ID to the item.                                         
1019      */                                                                                                  
1020     static void addItemToDatabase(Context context, final ItemInfo item, final long container,            
1021             final long screenId, final int cellX, final int cellY, final boolean notify) {               
1022         item.container = container;                                                                      
1023         item.cellX = cellX;                                                                              
1024         item.cellY = cellY;                                                                              
1025         // We store hotseat items in canonical form which is this orientation invariant position         
1026         // in the hotseat                                                                                
1027         if (context instanceof Launcher && screenId < 0 &&                                               
1028                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
1029             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1030         } else {                                                                                         
1031             item.screenId = screenId;                                                                    
1032         }                                                                                                
1033                                                                                                          
1034         final ContentValues values = new ContentValues();                                                
1035         final ContentResolver cr = context.getContentResolver();                                         
1036         item.onAddToDatabase(context, values);                                                           
1037                                                                                                          
1038         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1039         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1040                                                                                                          
1041         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
1042         Runnable r = new Runnable() {                                                                    
1043             public void run() {                                                                          
1044                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                              
1045                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                 
1046                                                                                                          
1047                 // Lock on mBgLock *after* the db operation                                              
1048                 synchronized (sBgLock) {                                                                 
1049                     checkItemInfoLocked(item.id, item, stackTrace);                                      
1050                     sBgItemsIdMap.put(item.id, item);                                                    
1051                     switch (item.itemType) {                                                             
1052                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1053                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1054                             // Fall through                                                              
1055                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1056                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1057                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1058                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1059                                 sBgWorkspaceItems.add(item);                                             
1060                             } else {                                                                     
1061                                 if (!sBgFolders.containsKey(item.container)) {                           
1062                                     // Adding an item to a folder that doesn't exist.                    
1063                                     String msg = "adding item: " + item + " to a folder that " +         
1064                                             " doesn't exist";                                            
1065                                     Log.e(TAG, msg);                                                     
1066                                 }                                                                        
1067                             }                                                                            
1068                             break;                                                                       
1069                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1070                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1071                             break;                                                                       
1072                     }                                                                                    
1073                 }                                                                                        
1074             }                                                                                            
1075         };                                                                                               
1076         runOnWorkerThread(r);                                                                            
1077     }                                                                                                    
1078                                                                                                          
1079     /**                                                                                                  
1080      * Creates a new unique child id, for a given cell span across all layouts.                          
1081      */                                                                                                  
1082     static int getCellLayoutChildId(                                                                     
1083             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1084         return (((int) container & 0xFF) << 24)                                                          
1085                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1086     }                                                                                                    
1087                                                                                                          
1088     private static ArrayList<ItemInfo> getItemsByPackageName(                                            
1089             final String pn, final UserHandleCompat user) {                                              
1090         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
1091             @Override                                                                                    
1092             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
1093                 return cn.getPackageName().equals(pn) && info.user.equals(user);                         
1094             }                                                                                            
1095         };                                                                                               
1096         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
1097     }                                                                                                    
1098                                                                                                          
1099     /**                                                                                                  
1100      * Removes all the items from the database corresponding to the specified package.                   
1101      */                                                                                                  
1102     static void deletePackageFromDatabase(Context context, final String pn,                              
1103             final UserHandleCompat user) {                                                               
1104         deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                               
1105     }                                                                                                    
1106                                                                                                          
1107     /**                                                                                                  
1108      * Removes the specified item from the database                                                      
1109      * @param context                                                                                    
1110      * @param item                                                                                       
1111      */                                                                                                  
1112     static void deleteItemFromDatabase(Context context, final ItemInfo item) {                           
1113         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1114         items.add(item);                                                                                 
1115         deleteItemsFromDatabase(context, items);                                                         
1116     }                                                                                                    
1117                                                                                                          
1118     /**                                                                                                  
1119      * Removes the specified items from the database                                                     
1120      * @param context                                                                                    
1121      * @param item                                                                                       
1122      */                                                                                                  
1123     static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {    
1124         final ContentResolver cr = context.getContentResolver();                                         
1125         Runnable r = new Runnable() {                                                                    
1126             public void run() {                                                                          
1127                 for (ItemInfo item : items) {                                                            
1128                     final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);            
1129                     cr.delete(uri, null, null);                                                          
1130                     // Lock on mBgLock *after* the db operation                                          
1131                     synchronized(sBgLock) {                                                              
1132                         switch (item.itemType) {                                                         
1133                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                           
1134                                 sBgFolders.remove(item.id);                                              
1135                                 for (ItemInfo info : sBgItemsIdMap.values()) {                           
1136                                     if (info.container == item.id) {                                     
1137                                         // We are deleting a folder which still contains items that      
1138                                         // think they are contained by that folder.                      
1139                                         String msg = (((("deleting a folder (" + item) + ") which still "🔵
1140                                         Log.e(TAG, msg);                                                 
1141                                     }                                                                    
1142                                 }                                                                        
1143                                 sBgWorkspaceItems.remove(item);                                          
1144                                 break;                                                                   
1145                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                      
1146                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                         
1147                                 sBgWorkspaceItems.remove(item);                                          
1148                                 break;                                                                   
1149                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET :                        
1150                                 sBgAppWidgets.remove(((LauncherAppWidgetInfo) (item)));                  
1151                                 break;                                                                   
1152                         }                                                                                
1153                         sBgItemsIdMap.remove(item.id);                                                   
1154                     }                                                                                    
1155                 }                                                                                        
1156             }                                                                                            
1157         };                                                                                               
1158         runOnWorkerThread(r);                                                                            
1159     }                                                                                                    
1160                                                                                                          
1161     /**                                                                                                  
1162      * Update the order of the workspace screens in the database. The array list contains                
1163      * a list of screen ids in the order that they should appear.                                        
1164      */                                                                                                  
1165     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1166         // Log to disk                                                                                   
1167         Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                       
1168         Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);        
1169                                                                                                          
1170         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1171         final ContentResolver cr = context.getContentResolver();                                         
1172         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1173                                                                                                          
1174         // Remove any negative screen ids -- these aren't persisted                                      
1175         Iterator<Long> iter = screensCopy.iterator();                                                    
1176         while (iter.hasNext()) {                                                                         
1177             long id = iter.next();                                                                       
1178             if (id < 0) {                                                                                
1179                 iter.remove();                                                                           
1180             }                                                                                            
1181         }                                                                                                
1182                                                                                                          
1183         Runnable r = new Runnable() {                                                                    
1184             @Override                                                                                    
1185             public void run() {                                                                          
1186                 ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();     
1187                 // Clear the table                                                                       
1188                 ops.add(ContentProviderOperation.newDelete(uri).build());                                
1189                 int count = screensCopy.size();                                                          
1190                 for (int i = 0; i < count; i++) {                                                        
1191                     ContentValues v = new ContentValues();                                               
1192                     long screenId = screensCopy.get(i);                                                  
1193                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1194                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1195                     ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());              
1196                 }                                                                                        
1197                                                                                                          
1198                 try {                                                                                    
1199                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
1200                 } catch (Exception ex) {                                                                 
1201                     throw new RuntimeException(ex);                                                      
1202                 }                                                                                        
1203                                                                                                          
1204                 synchronized (sBgLock) {                                                                 
1205                     sBgWorkspaceScreens.clear();                                                         
1206                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1207                 }                                                                                        
1208             }                                                                                            
1209         };                                                                                               
1210         runOnWorkerThread(r);                                                                            
1211     }                                                                                                    
1212                                                                                                          
1213     /**                                                                                                  
1214      * Remove the contents of the specified folder from the database                                     
1215      */                                                                                                  
1216     static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {               
1217         final ContentResolver cr = context.getContentResolver();                                         
1218         Runnable r = new Runnable() {                                                                    
1219             public void run() {                                                                          
1220                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);         
1221                 // Lock on mBgLock *after* the db operation                                              
1222                 synchronized(sBgLock) {                                                                  
1223                     sBgItemsIdMap.remove(info.id);                                                       
1224                     sBgFolders.remove(info.id);                                                          
1225                     sBgWorkspaceItems.remove(info);                                                      
1226                 }                                                                                        
1227                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, (LauncherSettings.Favor🔵
1228                 // Lock on mBgLock *after* the db operation                                              
1229                 synchronized(sBgLock) {                                                                  
1230                     for (ItemInfo childInfo : info.contents) {                                           
1231                         sBgItemsIdMap.remove(childInfo.id);                                              
1232                     }                                                                                    
1233                 }                                                                                        
1234             }                                                                                            
1235         };                                                                                               
1236         runOnWorkerThread(r);                                                                            
1237     }                                                                                                    
1238                                                                                                          
1239     /**                                                                                                  
1240      * Set this as the current Launcher activity object for the loader.                                  
1241      */                                                                                                  
1242     public void initialize(Callbacks callbacks) {                                                        
1243         synchronized (mLock) {                                                                           
1244             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1245         }                                                                                                
1246     }                                                                                                    
1247                                                                                                          
1248     @Override                                                                                            
1249     public void onPackageChanged(String packageName, UserHandleCompat user) {                            
1250         int op = PackageUpdatedTask.OP_UPDATE;                                                           
1251         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1252                 user));                                                                                  
1253     }                                                                                                    
1254                                                                                                          
1255     @Override                                                                                            
1256     public void onPackageRemoved(String packageName, UserHandleCompat user) {                            
1257         int op = PackageUpdatedTask.OP_REMOVE;                                                           
1258         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1259                 user));                                                                                  
1260     }                                                                                                    
1261                                                                                                          
1262     @Override                                                                                            
1263     public void onPackageAdded(String packageName, UserHandleCompat user) {                              
1264         int op = PackageUpdatedTask.OP_ADD;                                                              
1265         enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                   
1266                 user));                                                                                  
1267     }                                                                                                    
1268                                                                                                          
1269     @Override                                                                                            
1270     public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                        
1271             boolean replacing) {                                                                         
1272         if (!replacing) {                                                                                
1273             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,        
1274                     user));                                                                              
1275             if (mAppsCanBeOnRemoveableStorage) {                                                         
1276                 // Only rebind if we support removable storage. It catches the                           
1277                 // case where                                                                            
1278                 // apps on the external sd card need to be reloaded                                      
1279                 startLoaderFromBackground();                                                             
1280             }                                                                                            
1281         } else {                                                                                         
1282             // If we are replacing then just update the packages in the list                             
1283             enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                   
1284                     packageNames, user));                                                                
1285         }                                                                                                
1286     }                                                                                                    
1287                                                                                                          
1288     @Override                                                                                            
1289     public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                      
1290             boolean replacing) {                                                                         
1291         if (!replacing) {                                                                                
1292             enqueuePackageUpdated(new PackageUpdatedTask(                                                
1293                     PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                     
1294                     user));                                                                              
1295         }                                                                                                
1296     }                                                                                                    
1297                                                                                                          
1298     /**                                                                                                  
1299      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1300      * ACTION_PACKAGE_CHANGED.                                                                           
1301      */                                                                                                  
1302     @Override                                                                                            
1303     public void onReceive(Context context, Intent intent) {                                              
1304         if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                    
1305                                                                                                          
1306         final String action = intent.getAction();                                                        
1307         if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                               
1308             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1309             forceReload();                                                                               
1310         } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                 
1311              // Check if configuration change was an mcc/mnc change which would affect app resources     
1312              // and we would need to clear out the labels in all apps/workspace. Same handling as        
1313              // above for ACTION_LOCALE_CHANGED                                                          
1314              Configuration currentConfig = context.getResources().getConfiguration();                    
1315              if (mPreviousConfigMcc != currentConfig.mcc) {                                              
1316                    Log.d(TAG, "Reload apps on config change. curr_mcc:"                                  
1317                        + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                          
1318                    forceReload();                                                                        
1319              }                                                                                           
1320              // Update previousConfig                                                                    
1321              mPreviousConfigMcc = currentConfig.mcc;                                                     
1322         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1323                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1324             Callbacks callbacks = getCallback();                                                         
1325             if (callbacks != null) {                                                                     
1326                 callbacks.bindSearchablesChanged();                                                      
1327             }                                                                                            
1328         }                                                                                                
1329     }                                                                                                    
1330                                                                                                          
1331     void forceReload() {                                                                                 
1332         resetLoadedState(true, true);                                                                    
1333                                                                                                          
1334         // Do this here because if the launcher activity is running it will be restarted.                
1335         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1336         // to reload.                                                                                    
1337         startLoaderFromBackground();                                                                     
1338     }                                                                                                    
1339                                                                                                          
1340     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1341         synchronized (mLock) {                                                                           
1342             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1343             // mWorkspaceLoaded to true later                                                            
1344             stopLoaderLocked();                                                                          
1345             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1346             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1347         }                                                                                                
1348     }                                                                                                    
1349                                                                                                          
1350     /**                                                                                                  
1351      * When the launcher is in the background, it's possible for it to miss paired                       
1352      * configuration changes.  So whenever we trigger the loader from the background                     
1353      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1354      * of doing it now.                                                                                  
1355      */                                                                                                  
1356     public void startLoaderFromBackground() {                                                            
1357         boolean runLoader = false;                                                                       
1358         Callbacks callbacks = getCallback();                                                             
1359         if (callbacks != null) {                                                                         
1360             // Only actually run the loader if they're not paused.                                       
1361             if (!callbacks.setLoadOnResume()) {                                                          
1362                 runLoader = true;                                                                        
1363             }                                                                                            
1364         }                                                                                                
1365         if (runLoader) {                                                                                 
1366             startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                          
1367         }                                                                                                
1368     }                                                                                                    
1369                                                                                                          
1370     // If there is already a loader task running, tell it to stop.                                       
1371     // returns true if isLaunching() was true on the old task                                            
1372     private boolean stopLoaderLocked() {                                                                 
1373         boolean isLaunching = false;                                                                     
1374         LoaderTask oldTask = mLoaderTask;                                                                
1375         if (oldTask != null) {                                                                           
1376             if (oldTask.isLaunching()) {                                                                 
1377                 isLaunching = true;                                                                      
1378             }                                                                                            
1379             oldTask.stopLocked();                                                                        
1380         }                                                                                                
1381         return isLaunching;                                                                              
1382     }                                                                                                    
1383                                                                                                          
1384     public boolean isCurrentCallbacks(Callbacks callbacks) {                                             
1385         return (mCallbacks != null && mCallbacks.get() == callbacks);                                    
1386     }                                                                                                    
1387                                                                                                          
1388     public void startLoader(boolean isLaunching, int synchronousBindPage) {                              
1389         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                 
1390     }                                                                                                    
1391                                                                                                          
1392     public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {               
1393         synchronized (mLock) {                                                                           
1394             if (DEBUG_LOADERS) {                                                                         
1395                 Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                    
1396             }                                                                                            
1397                                                                                                          
1398             // Clear any deferred bind-runnables from the synchronized load process                      
1399             // We must do this before any loading/binding is scheduled below.                            
1400             synchronized (mDeferredBindRunnables) {                                                      
1401                 mDeferredBindRunnables.clear();                                                          
1402             }                                                                                            
1403                                                                                                          
1404             // Don't bother to start the thread if we know it's not going to do anything                 
1405             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1406                 // If there is already one running, tell it to stop.                                     
1407                 // also, don't downgrade isLaunching if we're already running                            
1408                 isLaunching = isLaunching || stopLoaderLocked();                                         
1409                 mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                 
1410                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1411                         && mAllAppsLoaded && mWorkspaceLoaded) {                                         
1412                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1413                 } else {                                                                                 
1414                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1415                     sWorker.post(mLoaderTask);                                                           
1416                 }                                                                                        
1417             }                                                                                            
1418         }                                                                                                
1419     }                                                                                                    
1420                                                                                                          
1421     void bindRemainingSynchronousPages() {                                                               
1422         // Post the remaining side pages to be loaded                                                    
1423         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1424             Runnable[] deferredBindRunnables = null;                                                     
1425             synchronized (mDeferredBindRunnables) {                                                      
1426                 deferredBindRunnables = mDeferredBindRunnables.toArray(                                  
1427                         new Runnable[mDeferredBindRunnables.size()]);                                    
1428                 mDeferredBindRunnables.clear();                                                          
1429             }                                                                                            
1430             for (final Runnable r : deferredBindRunnables) {                                             
1431                 mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                          
1432             }                                                                                            
1433         }                                                                                                
1434     }                                                                                                    
1435                                                                                                          
1436     public void stopLoader() {                                                                           
1437         synchronized (mLock) {                                                                           
1438             if (mLoaderTask != null) {                                                                   
1439                 mLoaderTask.stopLocked();                                                                
1440             }                                                                                            
1441         }                                                                                                
1442     }                                                                                                    
1443                                                                                                          
1444     /**                                                                                                  
1445      * Loads the workspace screen ids in an ordered list.                                                
1446      */                                                                                                  
1447     private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                             
1448         final ContentResolver contentResolver = context.getContentResolver();                            
1449         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1450                                                                                                          
1451         // Get screens ordered by rank.                                                                  
1452         final Cursor sc = contentResolver.query(screensUri, null, null, null,                            
1453                 LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                          
1454         ArrayList<Long> screenIds = new ArrayList<Long>();                                               
1455         try {                                                                                            
1456             final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);         
1457             while (sc.moveToNext()) {                                                                    
1458                 try {                                                                                    
1459                     screenIds.add(sc.getLong(idIndex));                                                  
1460                 } catch (Exception e) {                                                                  
1461                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                         
1462                             + " - invalid screens: " + e, true);                                         
1463                 }                                                                                        
1464             }                                                                                            
1465         } finally {                                                                                      
1466             sc.close();                                                                                  
1467         }                                                                                                
1468         return screenIds;                                                                                
1469     }                                                                                                    
1470                                                                                                          
1471     public boolean isAllAppsLoaded() {                                                                   
1472         return mAllAppsLoaded;                                                                           
1473     }                                                                                                    
1474                                                                                                          
1475     boolean isLoadingWorkspace() {                                                                       
1476         synchronized (mLock) {                                                                           
1477             if (mLoaderTask != null) {                                                                   
1478                 return mLoaderTask.isLoadingWorkspace();                                                 
1479             }                                                                                            
1480         }                                                                                                
1481         return false;                                                                                    
1482     }                                                                                                    
1483                                                                                                          
1484     /**                                                                                                  
1485      * Runnable for the thread that loads the contents of the launcher:                                  
1486      *   - workspace icons                                                                               
1487      *   - widgets                                                                                       
1488      *   - all apps icons                                                                                
1489      */                                                                                                  
1490     private class LoaderTask implements Runnable {                                                       
1491         private Context mContext;                                                                        
1492                                                                                                          
1493         private boolean mIsLaunching;                                                                    
1494                                                                                                          
1495         private boolean mIsLoadingAndBindingWorkspace;                                                   
1496                                                                                                          
1497         private boolean mStopped;                                                                        
1498                                                                                                          
1499         private boolean mLoadAndBindStepFinished;                                                        
1500                                                                                                          
1501         private int mFlags;                                                                              
1502                                                                                                          
1503         LoaderTask(Context context, boolean isLaunching, int flags) {                                    
1504             mContext = context;                                                                          
1505             mIsLaunching = isLaunching;                                                                  
1506             mFlags = flags;                                                                              
1507         }                                                                                                
1508                                                                                                          
1509         boolean isLaunching() {                                                                          
1510             return mIsLaunching;                                                                         
1511         }                                                                                                
1512                                                                                                          
1513         boolean isLoadingWorkspace() {                                                                   
1514             return mIsLoadingAndBindingWorkspace;                                                        
1515         }                                                                                                
1516                                                                                                          
1517         private void loadAndBindWorkspace() {                                                            
1518             mIsLoadingAndBindingWorkspace = true;                                                        
1519                                                                                                          
1520             // Load the workspace                                                                        
1521             if (DEBUG_LOADERS) {                                                                         
1522                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1523             }                                                                                            
1524                                                                                                          
1525             if (!mWorkspaceLoaded) {                                                                     
1526                 loadWorkspace();                                                                         
1527                 synchronized (LoaderTask.this) {                                                         
1528                     if (mStopped) {                                                                      
1529                         return;                                                                          
1530                     }                                                                                    
1531                     mWorkspaceLoaded = true;                                                             
1532                 }                                                                                        
1533             }                                                                                            
1534                                                                                                          
1535             // Bind the workspace                                                                        
1536             bindWorkspace(-1);                                                                           
1537         }                                                                                                
1538                                                                                                          
1539         private void waitForIdle() {                                                                     
1540             // Wait until the either we're stopped or the other threads are done.                        
1541             // This way we don't start loading all apps until the workspace has settled                  
1542             // down.                                                                                     
1543             synchronized (LoaderTask.this) {                                                             
1544                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1545                                                                                                          
1546                 mHandler.postIdle(new Runnable() {                                                       
1547                         public void run() {                                                              
1548                             synchronized (LoaderTask.this) {                                             
1549                                 mLoadAndBindStepFinished = true;                                         
1550                                 if (DEBUG_LOADERS) {                                                     
1551                                     Log.d(TAG, "done with previous binding step");                       
1552                                 }                                                                        
1553                                 LoaderTask.this.notify();                                                
1554                             }                                                                            
1555                         }                                                                                
1556                     });                                                                                  
1557                                                                                                          
1558                 while (!mStopped && !mLoadAndBindStepFinished) {                                         
1559                     try {                                                                                
1560                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1561                         // wait no longer than 1sec at a time                                            
1562                         this.wait(1000);                                                                 
1563                     } catch (InterruptedException ex) {                                                  
1564                         // Ignore                                                                        
1565                     }                                                                                    
1566                 }                                                                                        
1567                 if (DEBUG_LOADERS) {                                                                     
1568                     Log.d(TAG, "waited "                                                                 
1569                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1570                             + "ms for previous step to finish binding");                                 
1571                 }                                                                                        
1572             }                                                                                            
1573         }                                                                                                
1574                                                                                                          
1575         void runBindSynchronousPage(int synchronousBindPage) {                                           
1576             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1577                 // Ensure that we have a valid page index to load synchronously                          
1578                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1579                         "valid page index");                                                             
1580             }                                                                                            
1581             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1582                 // Ensure that we don't try and bind a specified page when the pages have not been       
1583                 // loaded already (we should load everything asynchronously in that case)                
1584                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1585             }                                                                                            
1586             synchronized (mLock) {                                                                       
1587                 if (mIsLoaderTaskRunning) {                                                              
1588                     // Ensure that we are never running the background loading at this point since       
1589                     // we also touch the background collections                                          
1590                     throw new RuntimeException("Error! Background loading is already running");          
1591                 }                                                                                        
1592             }                                                                                            
1593                                                                                                          
1594             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1595             //      data structures, we can't allow any other thread to touch that data, but because     
1596             //      this call is synchronous, we can get away with not locking).                         
1597                                                                                                          
1598             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1599             // operations from the previous activity.  We need to ensure that all queued operations      
1600             // are executed before any synchronous binding work is done.                                 
1601             mHandler.flush();                                                                            
1602                                                                                                          
1603             // Divide the set of loaded items into those that we are binding synchronously, and          
1604             // everything else that is to be bound normally (asynchronously).                            
1605             bindWorkspace(synchronousBindPage);                                                          
1606             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1607             //      arise from that.                                                                     
1608             onlyBindAllApps();                                                                           
1609         }                                                                                                
1610                                                                                                          
1611         public void run() {                                                                              
1612             synchronized (mLock) {                                                                       
1613                 mIsLoaderTaskRunning = true;                                                             
1614             }                                                                                            
1615             // Optimize for end-user experience: if the Launcher is up and // running with the           
1616             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1617             // workspace first (default).                                                                
1618             keep_running: {                                                                              
1619                 // Elevate priority when Home launches for the first time to avoid                       
1620                 // starving at boot time. Staring at a blank home is not cool.                           
1621                 synchronized (mLock) {                                                                   
1622                     if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                        
1623                             (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                  
1624                     android.os.Process.setThreadPriority(mIsLaunching                                    
1625                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);     
1626                 }                                                                                        
1627                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1628                 loadAndBindWorkspace();                                                                  
1629                                                                                                          
1630                 if (mStopped) {                                                                          
1631                     break keep_running;                                                                  
1632                 }                                                                                        
1633                                                                                                          
1634                 // Whew! Hard work done.  Slow us down, and wait until the UI thread has                 
1635                 // settled down.                                                                         
1636                 synchronized (mLock) {                                                                   
1637                     if (mIsLaunching) {                                                                  
1638                         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");          
1639                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        
1640                     }                                                                                    
1641                 }                                                                                        
1642                 waitForIdle();                                                                           
1643                                                                                                          
1644                 // second step                                                                           
1645                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1646                 loadAndBindAllApps();                                                                    
1647                                                                                                          
1648                 // Restore the default thread priority after we are done loading items                   
1649                 synchronized (mLock) {                                                                   
1650                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1651                 }                                                                                        
1652             }                                                                                            
1653                                                                                                          
1654                                                                                                          
1655 <<<<<<< LEFT                                                                                             
1656             if (LauncherAppState.isDisableAllApps()) {                                                   
1657                 // Ensure that all the applications that are in the system are                           
1658                 // represented on the home screen.                                                       
1659                 verifyApplications();                                                                    
1660                                                                                                          
1661 ||||||| BASE                                                                                             
1662 /*d94z9sk0k4hf9j3ijd - note the base isn't actually empty, spork simply doesn't generate a base - gd930kw🔵
1663 =======                                                                                                  
1664                                                                                                          
1665             // Update the saved icons if necessary                                                       
1666             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1667             synchronized (sBgLock) {                                                                     
1668                 for (Object key : sBgDbIconCache.keySet()) {                                             
1669                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1670                 }                                                                                        
1671                 sBgDbIconCache.clear();                                                                  
1672                                                                                                          
1673 >>>>>>> RIGHT                                                                                            
1674             }                                                                                            
1675                                                                                                          
1676             // Clear out this reference, otherwise we end up holding it until all of the                 
1677             // callback runnables are done.                                                              
1678             mContext = null;                                                                             
1679                                                                                                          
1680             synchronized (mLock) {                                                                       
1681                 // If we are still the last one to be scheduled, remove ourselves.                       
1682                 if (mLoaderTask == this) {                                                               
1683                     mLoaderTask = null;                                                                  
1684                 }                                                                                        
1685                 mIsLoaderTaskRunning = false;                                                            
1686             }                                                                                            
1687         }                                                                                                
1688                                                                                                          
1689         public void stopLocked() {                                                                       
1690             synchronized (LoaderTask.this) {                                                             
1691                 mStopped = true;                                                                         
1692                 this.notify();                                                                           
1693             }                                                                                            
1694         }                                                                                                
1695                                                                                                          
1696         /**                                                                                              
1697          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1698          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1699          * object that was around when the deferred message was scheduled, and if there's                
1700          * a new Callbacks object around then also return null.  This will save us from                  
1701          * calling onto it with data that will be ignored.                                               
1702          */                                                                                              
1703         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1704             synchronized (mLock) {                                                                       
1705                 if (mStopped) {                                                                          
1706                     return null;                                                                         
1707                 }                                                                                        
1708                                                                                                          
1709                 if (mCallbacks == null) {                                                                
1710                     return null;                                                                         
1711                 }                                                                                        
1712                                                                                                          
1713                 final Callbacks callbacks = mCallbacks.get();                                            
1714                 if (callbacks != oldCallbacks) {                                                         
1715                     return null;                                                                         
1716                 }                                                                                        
1717                 if (callbacks == null) {                                                                 
1718                     Log.w(TAG, "no mCallbacks");                                                         
1719                     return null;                                                                         
1720                 }                                                                                        
1721                                                                                                          
1722                 return callbacks;                                                                        
1723             }                                                                                            
1724         }                                                                                                
1725                                                                                                          
1726         // check & update map of what's occupied; used to discard overlapping/invalid items              
1727         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {        
1728             LauncherAppState app = LauncherAppState.getInstance();                                       
1729             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1730             final int countX = (int) grid.numColumns;                                                    
1731             final int countY = (int) grid.numRows;                                                       
1732                                                                                                          
1733             long containerIndex = item.screenId;                                                         
1734             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1735                 // Return early if we detect that an item is under the hotseat button                    
1736                 if (mCallbacks == null ||                                                                
1737                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1738                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1739                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1740                             + item.cellY + ") occupied by all apps");                                    
1741                     return false;                                                                        
1742                 }                                                                                        
1743                                                                                                          
1744                 final ItemInfo[][] hotseatItems =                                                        
1745                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1746                                                                                                          
1747                 if (item.screenId >= grid.numHotseatIcons) {                                             
1748                     Log.e(TAG, "Error loading shortcut " + item                                          
1749                             + " into hotseat position " + item.screenId                                  
1750                             + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)            
1751                             + ")");                                                                      
1752                     return false;                                                                        
1753                 }                                                                                        
1754                                                                                                          
1755                 if (hotseatItems != null) {                                                              
1756                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1757                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1758                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1759                                 + item.cellY + ") occupied by "                                          
1760                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1761                                 [(int) item.screenId][0]);                                               
1762                             return false;                                                                
1763                     } else {                                                                             
1764                         hotseatItems[(int) item.screenId][0] = item;                                     
1765                         return true;                                                                     
1766                     }                                                                                    
1767                 } else {                                                                                 
1768                     final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];              
1769                     items[(int) item.screenId][0] = item;                                                
1770                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1771                     return true;                                                                         
1772                 }                                                                                        
1773             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1774                 // Skip further checking if it is not the hotseat or workspace container                 
1775                 return true;                                                                             
1776             }                                                                                            
1777                                                                                                          
1778             if (!occupied.containsKey(item.screenId)) {                                                  
1779                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1780                 occupied.put(item.screenId, items);                                                      
1781             }                                                                                            
1782                                                                                                          
1783             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1784             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1785                     item.cellX < 0 || item.cellY < 0 ||                                                  
1786                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1787                 Log.e(TAG, "Error loading shortcut " + item                                              
1788                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1789                         + item.cellX + "," + item.cellY                                                  
1790                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1791                 return false;                                                                            
1792             }                                                                                            
1793                                                                                                          
1794             // Check if any workspace icons overlap with each other                                      
1795             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1796                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1797                     if (screens[x][y] != null) {                                                         
1798                         Log.e(TAG, "Error loading shortcut " + item                                      
1799                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1800                             + x + "," + y                                                                
1801                             + ") occupied by "                                                           
1802                             + screens[x][y]);                                                            
1803                         return false;                                                                    
1804                     }                                                                                    
1805                 }                                                                                        
1806             }                                                                                            
1807             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1808                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1809                     screens[x][y] = item;                                                                
1810                 }                                                                                        
1811             }                                                                                            
1812                                                                                                          
1813             return true;                                                                                 
1814         }                                                                                                
1815                                                                                                          
1816         /** Clears all the sBg data structures */                                                        
1817         private void clearSBgDataStructures() {                                                          
1818             synchronized(sBgLock) {                                                                      
1819                 sBgWorkspaceItems.clear();                                                               
1820                 sBgAppWidgets.clear();                                                                   
1821                 sBgFolders.clear();                                                                      
1822                 sBgItemsIdMap.clear();                                                                   
1823                 sBgWorkspaceScreens.clear();                                                             
1824             }                                                                                            
1825         }                                                                                                
1826                                                                                                          
1827         private void loadWorkspace() {                                                                   
1828             // Log to disk                                                                               
1829             Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                
1830             final long t = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                             
1831             final Context context = mContext;                                                            
1832             final ContentResolver contentResolver = context.getContentResolver();                        
1833             final PackageManager manager = context.getPackageManager();                                  
1834             final boolean isSafeMode = manager.isSafeMode();                                             
1835             final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);             
1836             final boolean isSdCardReady = context.registerReceiver(null, new IntentFilter(StartupReceiver🔵
1837             LauncherAppState app = LauncherAppState.getInstance();                                       
1838             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1839             int countX = ((int) (grid.numColumns));                                                      
1840             int countY = ((int) (grid.numRows));                                                         
1841             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1842                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1843                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1844             }                                                                                            
1845             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1846                 // append the user's Launcher2 shortcuts                                                 
1847                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1848                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1849             } else {                                                                                     
1850                 // Make sure the default workspace is loaded                                             
1851                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1852                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                
1853             }                                                                                            
1854             synchronized(sBgLock) {                                                                      
1855                 clearSBgDataStructures();                                                                
1856                 final HashSet<String> installingPkgs = PackageInstallerCompat.getInstance(mContext).updat🔵
1857                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1858                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1859                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;           
1860                 if (DEBUG_LOADERS) {                                                                     
1861                     Log.d(TAG, "loading model from " + contentUri);                                      
1862                 }                                                                                        
1863                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1864                 // +1 for the hotseat (it can be larger than the workspace)                              
1865                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1866                 // before any earlier duplicates)                                                        
1867                 final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();          
1868                 try {                                                                                    
1869                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1870                     final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);  
1871                     final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);    
1872                     final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYP🔵
1873                     final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);      
1874                     final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_🔵
1875                     final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON🔵
1876                     final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAIN🔵
1877                     final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYP🔵
1878                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWI🔵
1879                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites🔵
1880                     final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);  
1881                     final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);    
1882                     final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);    
1883                     final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);    
1884                     final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);    
1885                     final int rankIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RANK);      
1886                     final int restoredIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED🔵
1887                     final int profileIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE🔵
1888                     // final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);     
1889                     // final int displayModeIndex = c.getColumnIndexOrThrow(                             
1890                     // LauncherSettings.Favorites.DISPLAY_MODE);                                         
1891                     ShortcutInfo info;                                                                   
1892                     String intentDescription;                                                            
1893                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1894                     int container;                                                                       
1895                     long id;                                                                             
1896                     Intent intent;                                                                       
1897                     UserHandleCompat user;                                                               
1898                     while ((!mStopped) && c.moveToNext()) {                                              
1899                         try {                                                                            
1900                             int itemType = c.getInt(itemTypeIndex);                                      
1901                             boolean restored = 0 != c.getInt(restoredIndex);                             
1902                             boolean allowMissingTarget = false;                                          
1903                             switch (itemType) {                                                          
1904                                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                  
1905                                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                     
1906                                     id = c.getLong(idIndex);                                             
1907                                     intentDescription = c.getString(intentIndex);                        
1908                                     long serialNumber = c.getInt(profileIdIndex);                        
1909                                     user = mUserManager.getUserForSerialNumber(serialNumber);            
1910                                     int promiseType = c.getInt(restoredIndex);                           
1911                                     int disabledState = 0;                                               
1912                                     boolean itemReplaced = false;                                        
1913                                     if (user == null) {                                                  
1914                                         // User has been deleted remove the item.                        
1915                                         itemsToRemove.add(id);                                           
1916                                         continue;                                                        
1917                                     }                                                                    
1918                                     try {                                                                
1919                                         intent = Intent.parseUri(intentDescription, 0);                  
1920                                         ComponentName cn = intent.getComponent();                        
1921                                         if ((cn != null) && (cn.getPackageName() != null)) {             
1922                                             boolean validPkg = launcherApps.isPackageEnabledForProfile(cn🔵
1923                                             boolean validComponent = validPkg && launcherApps.isActivityE🔵
1924                                             if (validComponent) {                                        
1925                                                 if (restored) {                                          
1926                                                     // no special handling necessary for this item       
1927                                                     restoredRows.add(id);                                
1928                                                     restored = false;                                    
1929                                                 }                                                        
1930                                             } else if (validPkg) {                                       
1931                                                 intent = null;                                           
1932                                                 if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 🔵
1933                                                     // We allow auto install apps to have their intent   
1934                                                     // updated after an install.                         
1935                                                     intent = manager.getLaunchIntentForPackage(cn.getPack🔵
1936                                                     if (intent != null) {                                
1937                                                         ContentValues values = new ContentValues();      
1938                                                         values.put(LauncherSettings.Favorites.INTENT, int🔵
1939                                                         updateItem(id, values);                          
1940                                                     }                                                    
1941                                                 }                                                        
1942                                                 if (intent == null) {                                    
1943                                                     // The app is installed but the component is no      
1944                                                     // longer available.                                 
1945                                                     Launcher.addDumpLog(TAG, "Invalid component removed: 🔵
1946                                                     itemsToRemove.add(id);                               
1947                                                     continue;                                            
1948                                                 } else {                                                 
1949                                                     // no special handling necessary for this item       
1950                                                     restoredRows.add(id);                                
1951                                                     restored = false;                                    
1952                                                 }                                                        
1953                                             } else if (restored) {                                       
1954                                                 // Package is not yet available but might be             
1955                                                 // installed later.                                      
1956                                                 Launcher.addDumpLog(TAG, "package not yet restored: " + c🔵
1957                                                 if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 🔵
1958                                                     // Restore has started once.                         
1959                                                 } else if (installingPkgs.contains(cn.getPackageName())) 🔵
1960                                                     // App restore has started. Update the flag          
1961                                                     promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;    
1962                                                     ContentValues values = new ContentValues();          
1963                                                     values.put(LauncherSettings.Favorites.RESTORED, promi🔵
1964                                                     updateItem(id, values);                              
1965                                                 } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_🔵
1966                                                     // This is a common app. Try to replace this.        
1967                                                     int appType = CommonAppTypeParser.decodeItemTypeFromF🔵
1968                                                     CommonAppTypeParser parser = new CommonAppTypeParser(🔵
1969                                                     if (parser.findDefaultApp()) {                       
1970                                                         // Default app found. Replace it.                
1971                                                         intent = parser.parsedIntent;                    
1972                                                         cn = intent.getComponent();                      
1973                                                         ContentValues values = parser.parsedValues;      
1974                                                         values.put(LauncherSettings.Favorites.RESTORED, 0🔵
1975                                                         updateItem(id, values);                          
1976                                                         restored = false;                                
1977                                                         itemReplaced = true;                             
1978                                                     } else if (REMOVE_UNRESTORED_ICONS) {                
1979                                                         Launcher.addDumpLog(TAG, "Unrestored package remo🔵
1980                                                         itemsToRemove.add(id);                           
1981                                                         continue;                                        
1982                                                     }                                                    
1983                                                 } else if (REMOVE_UNRESTORED_ICONS) {                    
1984                                                     Launcher.addDumpLog(TAG, "Unrestored package removed:🔵
1985                                                     itemsToRemove.add(id);                               
1986                                                     continue;                                            
1987                                                 }                                                        
1988                                             } else if (launcherApps.isAppEnabled(manager, cn.getPackageNa🔵
1989                                                 // Package is present but not available.                 
1990                                                 allowMissingTarget = true;                               
1991                                                 disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
1992                                             } else if (!isSdCardReady) {                                 
1993                                                 // SdCard is not ready yet. Package might get available, 
1994                                                 // once it is ready.                                     
1995                                                 Launcher.addDumpLog(TAG, ("Invalid package: " + cn) + " (🔵
1996                                                 HashSet<String> pkgs = sPendingPackages.get(user);       
1997                                                 if (pkgs == null) {                                      
1998                                                     pkgs = new HashSet<String>();                        
1999                                                     sPendingPackages.put(user, pkgs);                    
2000                                                 }                                                        
2001                                                 pkgs.add(cn.getPackageName());                           
2002                                                 allowMissingTarget = true;                               
2003                                                 // Add the icon on the workspace anyway.                 
2004                                             } else {                                                     
2005                                                 // Do not wait for external media load anymore.          
2006                                                 // Log the invalid package, and remove it                
2007                                                 Launcher.addDumpLog(TAG, "Invalid package removed: " + cn🔵
2008                                                 itemsToRemove.add(id);                                   
2009                                                 continue;                                                
2010                                             }                                                            
2011                                         } else if (cn == null) {                                         
2012                                             // For shortcuts with no component, keep them as they are    
2013                                             restoredRows.add(id);                                        
2014                                             restored = false;                                            
2015                                         }                                                                
2016                                     } catch (URISyntaxException e) {                                     
2017                                         Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, tru🔵
2018                                         continue;                                                        
2019                                     }                                                                    
2020                                     if (itemReplaced) {                                                  
2021                                         if (user.equals(UserHandleCompat.myUserHandle())) {              
2022                                             info = getAppShortcutInfo(manager, intent, user, context, nul🔵
2023                                         } else {                                                         
2024                                             // Don't replace items for other profiles.                   
2025                                             itemsToRemove.add(id);                                       
2026                                             continue;                                                    
2027                                         }                                                                
2028                                     } else if (restored) {                                               
2029                                         if (user.equals(UserHandleCompat.myUserHandle())) {              
2030                                             Launcher.addDumpLog(TAG, "constructing info for partially res🔵
2031                                             info = getRestoredItemInfo(c, titleIndex, intent, promiseType🔵
2032                                             intent = getRestoredItemIntent(c, context, intent);          
2033                                         } else {                                                         
2034                                             // Don't restore items for other profiles.                   
2035                                             itemsToRemove.add(id);                                       
2036                                             continue;                                                    
2037                                         }                                                                
2038                                     } else if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATI🔵
2039                                         info = getAppShortcutInfo(manager, intent, user, context, c, icon🔵
2040                                     } else {                                                             
2041                                         info = getShortcutInfo(c, context, iconTypeIndex, iconPackageInde🔵
2042                                         // App shortcuts that used to be automatically added to Launcher 
2043                                         // didn't always have the correct intent flags set, so do that   
2044                                         // here                                                          
2045                                         if ((((intent.getAction() != null) && (intent.getCategories() != 🔵
2046                                             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_A🔵
2047                                         }                                                                
2048                                     }                                                                    
2049                                     if (info != null) {                                                  
2050                                         info.id = id;                                                    
2051                                         info.intent = intent;                                            
2052                                         container = c.getInt(containerIndex);                            
2053                                         info.container = container;                                      
2054                                         info.screenId = c.getInt(screenIndex);                           
2055                                         info.cellX = c.getInt(cellXIndex);                               
2056                                         info.cellY = c.getInt(cellYIndex);                               
2057                                         info.rank = c.getInt(rankIndex);                                 
2058                                         info.spanX = 1;                                                  
2059                                         info.spanY = 1;                                                  
2060                                         info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);      
2061                                         info.isDisabled = disabledState;                                 
2062                                         if (isSafeMode && (!Utilities.isSystemApp(context, intent))) {   
2063                                             info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;      
2064                                         }                                                                
2065                                         // check & update map of what's occupied                         
2066                                         if (!checkItemPlacement(occupied, info)) {                       
2067                                             itemsToRemove.add(id);                                       
2068                                             break;                                                       
2069                                         }                                                                
2070                                         switch (container) {                                             
2071                                             case LauncherSettings.Favorites.CONTAINER_DESKTOP :          
2072                                             case LauncherSettings.Favorites.CONTAINER_HOTSEAT :          
2073                                                 sBgWorkspaceItems.add(info);                             
2074                                                 break;                                                   
2075                                             default :                                                    
2076                                                 // Item is in a user folder                              
2077                                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, cont🔵
2078                                                 folderInfo.add(info);                                    
2079                                                 break;                                                   
2080                                         }                                                                
2081                                         sBgItemsIdMap.put(info.id, info);                                
2082                                     } else {                                                             
2083                                         throw new RuntimeException("Unexpected null ShortcutInfo");      
2084                                     }                                                                    
2085                                     break;                                                               
2086                                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                       
2087                                     id = c.getLong(idIndex);                                             
2088                                     FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);            
2089                                     folderInfo.title = c.getString(titleIndex);                          
2090                                     folderInfo.id = id;                                                  
2091                                     container = c.getInt(containerIndex);                                
2092                                     folderInfo.container = container;                                    
2093                                     folderInfo.screenId = c.getInt(screenIndex);                         
2094                                     folderInfo.cellX = c.getInt(cellXIndex);                             
2095                                     folderInfo.cellY = c.getInt(cellYIndex);                             
2096                                     folderInfo.spanX = 1;                                                
2097                                     folderInfo.spanY = 1;                                                
2098                                     // check & update map of what's occupied                             
2099                                     if (!checkItemPlacement(occupied, folderInfo)) {                     
2100                                         itemsToRemove.add(id);                                           
2101                                         break;                                                           
2102                                     }                                                                    
2103                                     switch (container) {                                                 
2104                                         case LauncherSettings.Favorites.CONTAINER_DESKTOP :              
2105                                         case LauncherSettings.Favorites.CONTAINER_HOTSEAT :              
2106                                             sBgWorkspaceItems.add(folderInfo);                           
2107                                             break;                                                       
2108                                     }                                                                    
2109                                     if (restored) {                                                      
2110                                         // no special handling required for restored folders             
2111                                         restoredRows.add(id);                                            
2112                                     }                                                                    
2113                                     sBgItemsIdMap.put(folderInfo.id, folderInfo);                        
2114                                     sBgFolders.put(folderInfo.id, folderInfo);                           
2115                                     break;                                                               
2116                                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET :                    
2117                                 case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET :             
2118                                     // Read all Launcher-specific widget details                         
2119                                     boolean customWidget = itemType == LauncherSettings.Favorites.ITEM_TY🔵
2120                                     int appWidgetId = c.getInt(appWidgetIdIndex);                        
2121                                     String savedProvider = c.getString(appWidgetProviderIndex);          
2122                                     id = c.getLong(idIndex);                                             
2123                                     final ComponentName component = ComponentName.unflattenFromString(sav🔵
2124                                     final int restoreStatus = c.getInt(restoredIndex);                   
2125                                     final boolean isIdValid = (restoreStatus & LauncherAppWidgetInfo.FLAG🔵
2126                                     final boolean wasProviderReady = (restoreStatus & LauncherAppWidgetIn🔵
2127                                     final LauncherAppWidgetProviderInfo provider = LauncherModel.getProvi🔵
2128                                     final boolean isProviderReady = isValidProvider(provider);           
2129                                     if ((((!isSafeMode) && (!customWidget)) && wasProviderReady) && (!isP🔵
2130                                         String log = ((("Deleting widget that isn't installed anymore: " 🔵
2131                                         Log.e(TAG, log);                                                 
2132                                         Launcher.addDumpLog(TAG, log, false);                            
2133                                         itemsToRemove.add(id);                                           
2134                                     } else {                                                             
2135                                         if (isProviderReady) {                                           
2136                                             appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, provid🔵
2137                                             if (!customWidget) {                                         
2138                                                 int[] minSpan = Launcher.getMinSpanForWidget(context, pro🔵
2139                                                 appWidgetInfo.minSpanX = minSpan[0];                     
2140                                                 appWidgetInfo.minSpanY = minSpan[1];                     
2141                                             }                                                            
2142                                             int status = restoreStatus;                                  
2143                                             if (!wasProviderReady) {                                     
2144                                                 // If provider was not previously ready, update the      
2145                                                 // status and UI flag.                                   
2146                                                 // Id would be valid only if the widget restore broadcast🔵
2147                                                 if (isIdValid) {                                         
2148                                                     status = LauncherAppWidgetInfo.RESTORE_COMPLETED;    
2149                                                 } else {                                                 
2150                                                     status &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_RE🔵
2151                                                 }                                                        
2152                                             }                                                            
2153                                             appWidgetInfo.restoreStatus = status;                        
2154                                         } else {                                                         
2155                                             Log.v(TAG, (((("Widget restore pending id=" + id) + " appWidg🔵
2156                                             appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, compon🔵
2157                                             appWidgetInfo.restoreStatus = restoreStatus;                 
2158                                             if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_START🔵
2159                                                 // Restore has started once.                             
2160                                             } else if (installingPkgs.contains(component.getPackageName()🔵
2161                                                 // App restore has started. Update the flag              
2162                                                 appWidgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG🔵
2163                                             } else if (REMOVE_UNRESTORED_ICONS && (!isSafeMode)) {       
2164                                                 Launcher.addDumpLog(TAG, "Unrestored widget removed: " + 🔵
2165                                                 itemsToRemove.add(id);                                   
2166                                                 continue;                                                
2167                                             }                                                            
2168                                         }                                                                
2169                                         appWidgetInfo.id = id;                                           
2170                                         appWidgetInfo.screenId = c.getInt(screenIndex);                  
2171                                         appWidgetInfo.cellX = c.getInt(cellXIndex);                      
2172                                         appWidgetInfo.cellY = c.getInt(cellYIndex);                      
2173                                         appWidgetInfo.spanX = c.getInt(spanXIndex);                      
2174                                         appWidgetInfo.spanY = c.getInt(spanYIndex);                      
2175                                         if (!customWidget) {                                             
2176                                             int[] minSpan = Launcher.getMinSpanForWidget(context, provide🔵
2177                                             appWidgetInfo.minSpanX = minSpan[0];                         
2178                                             appWidgetInfo.minSpanY = minSpan[1];                         
2179                                         }                                                                
2180                                         container = c.getInt(containerIndex);                            
2181                                         if ((container != LauncherSettings.Favorites.CONTAINER_DESKTOP) &🔵
2182                                             Log.e(TAG, "Widget found where container != " + "CONTAINER_DE🔵
2183                                             continue;                                                    
2184                                         }                                                                
2185                                         appWidgetInfo.container = c.getInt(containerIndex);              
2186                                         // check & update map of what's occupied                         
2187                                         if (!checkItemPlacement(occupied, appWidgetInfo)) {              
2188                                             itemsToRemove.add(id);                                       
2189                                             break;                                                       
2190                                         }                                                                
2191                                         if (!customWidget) {                                             
2192                                             String providerName = appWidgetInfo.providerName.flattenToStr🔵
2193                                             if ((!providerName.equals(savedProvider)) || (appWidgetInfo.r🔵
2194                                                 ContentValues values = new ContentValues();              
2195                                                 values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,🔵
2196                                                 values.put(LauncherSettings.Favorites.RESTORED, appWidget🔵
2197                                                 updateItem(id, values);                                  
2198                                             }                                                            
2199                                         }                                                                
2200                                         sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);              
2201                                         sBgAppWidgets.add(appWidgetInfo);                                
2202                                     }                                                                    
2203                                     break;                                                               
2204                             }                                                                            
2205                         } catch (java.lang.Exception e) {                                                
2206                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2207                         }                                                                                
2208                     }                                                                                    
2209                 } finally {                                                                              
2210                     if (c != null) {                                                                     
2211                         c.close();                                                                       
2212                     }                                                                                    
2213                 }                                                                                        
2214                 // Break early if we've stopped loading                                                  
2215                 if (mStopped) {                                                                          
2216                     clearSBgDataStructures();                                                            
2217                     return;                                                                              
2218                 }                                                                                        
2219                 if (itemsToRemove.size() > 0) {                                                          
2220                     ContentProviderClient client = contentResolver.acquireContentProviderClient(contentUr🔵
2221                     // Remove dead items                                                                 
2222                     for (long id : itemsToRemove) {                                                      
2223                         if (DEBUG_LOADERS) {                                                             
2224                             Log.d(TAG, "Removed id = " + id);                                            
2225                         }                                                                                
2226                         // Don't notify content observers                                                
2227                         try {                                                                            
2228                             client.delete(LauncherSettings.Favorites.getContentUri(id, false), null, null🔵
2229                         } catch (RemoteException e) {                                                    
2230                             Log.w(TAG, "Could not remove id = " + id);                                   
2231                         }                                                                                
2232                     }                                                                                    
2233                 }                                                                                        
2234                 if (restoredRows.size() > 0) {                                                           
2235                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(contentU🔵
2236                     // Update restored items that no longer require special handling                     
2237                     try {                                                                                
2238                         StringBuilder selectionBuilder = new StringBuilder();                            
2239                         selectionBuilder.append(LauncherSettings.Favorites._ID);                         
2240                         selectionBuilder.append(" IN (");                                                
2241                         selectionBuilder.append(TextUtils.join(", ", restoredRows));                     
2242                         selectionBuilder.append(")");                                                    
2243                         ContentValues values = new ContentValues();                                      
2244                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2245                         updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values, se🔵
2246                     } catch (RemoteException e) {                                                        
2247                         Log.w(TAG, "Could not update restored rows");                                    
2248                     }                                                                                    
2249                 }                                                                                        
2250                 if ((!isSdCardReady) && (!sPendingPackages.isEmpty())) {                                 
2251                     context.registerReceiver(new AppsAvailabilityCheck(), new IntentFilter(StartupReceive🔵
2252                 }                                                                                        
2253                 sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                            
2254                 // Log to disk                                                                           
2255                 Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " + TextUtils.join(", ", sBgW🔵
2256                 // Remove any empty screens                                                              
2257                 ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                
2258                 for (ItemInfo item : sBgItemsIdMap.values()) {                                           
2259                     long screenId = item.screenId;                                                       
2260                     if ((item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) && unusedScreens🔵
2261                         unusedScreens.remove(screenId);                                                  
2262                     }                                                                                    
2263                 }                                                                                        
2264                 // If there are any empty screens remove them, and update.                               
2265                 if (unusedScreens.size() != 0) {                                                         
2266                     // Log to disk                                                                       
2267                     Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " + TextUtils.j🔵
2268                     sBgWorkspaceScreens.removeAll(unusedScreens);                                        
2269                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2270                 }                                                                                        
2271                 if (DEBUG_LOADERS) {                                                                     
2272                     Log.d(TAG, ("loaded workspace in " + (SystemClock.uptimeMillis() - t)) + "ms");      
2273                     Log.d(TAG, "workspace layout: ");                                                    
2274                     int nScreens = occupied.size();                                                      
2275                     for (int y = 0; y < countY; y++) {                                                   
2276                         String line = "";                                                                
2277                         Iterator<Long> iter = occupied.keySet().iterator();                              
2278                         while (iter.hasNext()) {                                                         
2279                             long screenId = iter.next();                                                 
2280                             if (screenId > 0) {                                                          
2281                                 line += " | ";                                                           
2282                             }                                                                            
2283                             for (int x = 0; x < countX; x++) {                                           
2284                                 ItemInfo[][] screen = occupied.get(screenId);                            
2285                                 if ((x < screen.length) && (y < screen[x].length)) {                     
2286                                     line += (screen[x][y] != null) ? "#" : ".";                          
2287                                 } else {                                                                 
2288                                     line += "!";                                                         
2289                                 }                                                                        
2290                             }                                                                            
2291                         }                                                                                
2292                         Log.d(TAG, ("[ " + line) + " ]");                                                
2293                     }                                                                                    
2294                 }                                                                                        
2295             }                                                                                            
2296         }                                                                                                
2297                                                                                                          
2298         /**                                                                                              
2299          * Partially updates the item without any notification. Must be called on the worker thread.     
2300          */                                                                                              
2301         private void updateItem(long itemId, ContentValues update) {                                     
2302             mContext.getContentResolver().update(                                                        
2303                     LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                              
2304                     update,                                                                              
2305                     BaseColumns._ID + "= ?",                                                             
2306                     new String[]{Long.toString(itemId)});                                                
2307         }                                                                                                
2308                                                                                                          
2309         /** Filters the set of items who are directly or indirectly (via another container) on the       
2310          * specified screen. */                                                                          
2311         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2312                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2313                 ArrayList<ItemInfo> currentScreenItems,                                                  
2314                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2315             // Purge any null ItemInfos                                                                  
2316             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2317             while (iter.hasNext()) {                                                                     
2318                 ItemInfo i = iter.next();                                                                
2319                 if (i == null) {                                                                         
2320                     iter.remove();                                                                       
2321                 }                                                                                        
2322             }                                                                                            
2323                                                                                                          
2324             // Order the set of items by their containers first, this allows use to walk through the     
2325             // list sequentially, build up a list of containers that are in the specified screen,        
2326             // as well as all items in those containers.                                                 
2327             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2328             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2329                 @Override                                                                                
2330                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2331                     return (int) (lhs.container - rhs.container);                                        
2332                 }                                                                                        
2333             });                                                                                          
2334             for (ItemInfo info : allWorkspaceItems) {                                                    
2335                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2336                     if (info.screenId == currentScreenId) {                                              
2337                         currentScreenItems.add(info);                                                    
2338                         itemsOnScreen.add(info.id);                                                      
2339                     } else {                                                                             
2340                         otherScreenItems.add(info);                                                      
2341                     }                                                                                    
2342                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2343                     currentScreenItems.add(info);                                                        
2344                     itemsOnScreen.add(info.id);                                                          
2345                 } else {                                                                                 
2346                     if (itemsOnScreen.contains(info.container)) {                                        
2347                         currentScreenItems.add(info);                                                    
2348                         itemsOnScreen.add(info.id);                                                      
2349                     } else {                                                                             
2350                         otherScreenItems.add(info);                                                      
2351                     }                                                                                    
2352                 }                                                                                        
2353             }                                                                                            
2354         }                                                                                                
2355                                                                                                          
2356         /** Filters the set of widgets which are on the specified screen. */                             
2357         private void filterCurrentAppWidgets(long currentScreenId,                                       
2358                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2359                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2360                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2361                                                                                                          
2362             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2363                 if (widget == null) continue;                                                            
2364                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2365                         widget.screenId == currentScreenId) {                                            
2366                     currentScreenWidgets.add(widget);                                                    
2367                 } else {                                                                                 
2368                     otherScreenWidgets.add(widget);                                                      
2369                 }                                                                                        
2370             }                                                                                            
2371         }                                                                                                
2372                                                                                                          
2373         /** Filters the set of folders which are on the specified screen. */                             
2374         private void filterCurrentFolders(long currentScreenId,                                          
2375                 HashMap<Long, ItemInfo> itemsIdMap,                                                      
2376                 HashMap<Long, FolderInfo> folders,                                                       
2377                 HashMap<Long, FolderInfo> currentScreenFolders,                                          
2378                 HashMap<Long, FolderInfo> otherScreenFolders) {                                          
2379                                                                                                          
2380             for (long id : folders.keySet()) {                                                           
2381                 ItemInfo info = itemsIdMap.get(id);                                                      
2382                 FolderInfo folder = folders.get(id);                                                     
2383                 if (info == null || folder == null) continue;                                            
2384                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2385                         info.screenId == currentScreenId) {                                              
2386                     currentScreenFolders.put(id, folder);                                                
2387                 } else {                                                                                 
2388                     otherScreenFolders.put(id, folder);                                                  
2389                 }                                                                                        
2390             }                                                                                            
2391         }                                                                                                
2392                                                                                                          
2393         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2394          * right) */                                                                                     
2395         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2396             final LauncherAppState app = LauncherAppState.getInstance();                                 
2397             final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                          
2398             // XXX: review this                                                                          
2399             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2400                 @Override                                                                                
2401                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2402                     int cellCountX = (int) grid.numColumns;                                              
2403                     int cellCountY = (int) grid.numRows;                                                 
2404                     int screenOffset = cellCountX * cellCountY;                                          
2405                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2406                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2407                             lhs.cellY * cellCountX + lhs.cellX);                                         
2408                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2409                             rhs.cellY * cellCountX + rhs.cellX);                                         
2410                     return (int) (lr - rr);                                                              
2411                 }                                                                                        
2412             });                                                                                          
2413         }                                                                                                
2414                                                                                                          
2415         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2416                 final ArrayList<Long> orderedScreens) {                                                  
2417             final Runnable r = new Runnable() {                                                          
2418                 @Override                                                                                
2419                 public void run() {                                                                      
2420                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2421                     if (callbacks != null) {                                                             
2422                         callbacks.bindScreens(orderedScreens);                                           
2423                     }                                                                                    
2424                 }                                                                                        
2425             };                                                                                           
2426             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2427         }                                                                                                
2428                                                                                                          
2429         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2430                 final ArrayList<ItemInfo> workspaceItems,                                                
2431                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2432                 final HashMap<Long, FolderInfo> folders,                                                 
2433                 ArrayList<Runnable> deferredBindRunnables) {                                             
2434                                                                                                          
2435             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2436                                                                                                          
2437             // Bind the workspace items                                                                  
2438             int N = workspaceItems.size();                                                               
2439             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2440                 final int start = i;                                                                     
2441                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2442                 final Runnable r = new Runnable() {                                                      
2443                     @Override                                                                            
2444                     public void run() {                                                                  
2445                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2446                         if (callbacks != null) {                                                         
2447                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2448                                     false);                                                              
2449                         }                                                                                
2450                     }                                                                                    
2451                 };                                                                                       
2452                 if (postOnMainThread) {                                                                  
2453                     synchronized (deferredBindRunnables) {                                               
2454                         deferredBindRunnables.add(r);                                                    
2455                     }                                                                                    
2456                 } else {                                                                                 
2457                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2458                 }                                                                                        
2459             }                                                                                            
2460                                                                                                          
2461             // Bind the folders                                                                          
2462             if (!folders.isEmpty()) {                                                                    
2463                 final Runnable r = new Runnable() {                                                      
2464                     public void run() {                                                                  
2465                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2466                         if (callbacks != null) {                                                         
2467                             callbacks.bindFolders(folders);                                              
2468                         }                                                                                
2469                     }                                                                                    
2470                 };                                                                                       
2471                 if (postOnMainThread) {                                                                  
2472                     synchronized (deferredBindRunnables) {                                               
2473                         deferredBindRunnables.add(r);                                                    
2474                     }                                                                                    
2475                 } else {                                                                                 
2476                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2477                 }                                                                                        
2478             }                                                                                            
2479                                                                                                          
2480             // Bind the widgets, one at a time                                                           
2481             N = appWidgets.size();                                                                       
2482             for (int i = 0; i < N; i++) {                                                                
2483                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2484                 final Runnable r = new Runnable() {                                                      
2485                     public void run() {                                                                  
2486                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2487                         if (callbacks != null) {                                                         
2488                             callbacks.bindAppWidget(widget);                                             
2489                         }                                                                                
2490                     }                                                                                    
2491                 };                                                                                       
2492                 if (postOnMainThread) {                                                                  
2493                     deferredBindRunnables.add(r);                                                        
2494                 } else {                                                                                 
2495                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2496                 }                                                                                        
2497             }                                                                                            
2498         }                                                                                                
2499                                                                                                          
2500         /**                                                                                              
2501          * Binds all loaded data to actual views on the main thread.                                     
2502          */                                                                                              
2503         private void bindWorkspace(int synchronizeBindPage) {                                            
2504             final long t = SystemClock.uptimeMillis();                                                   
2505             Runnable r;                                                                                  
2506                                                                                                          
2507             // Don't use these two variables in any of the callback runnables.                           
2508             // Otherwise we hold a reference to them.                                                    
2509             final Callbacks oldCallbacks = mCallbacks.get();                                             
2510             if (oldCallbacks == null) {                                                                  
2511                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2512                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2513                 return;                                                                                  
2514             }                                                                                            
2515                                                                                                          
2516             // Save a copy of all the bg-thread collections                                              
2517             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2518             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2519                     new ArrayList<LauncherAppWidgetInfo>();                                              
2520             HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                         
2521             HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                          
2522             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2523             synchronized (sBgLock) {                                                                     
2524                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2525                 appWidgets.addAll(sBgAppWidgets);                                                        
2526                 folders.putAll(sBgFolders);                                                              
2527                 itemsIdMap.putAll(sBgItemsIdMap);                                                        
2528                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2529             }                                                                                            
2530                                                                                                          
2531             final boolean isLoadingSynchronously =                                                       
2532                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2533             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2534                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2535             if (currScreen >= orderedScreenIds.size()) {                                                 
2536                 // There may be no workspace screens (just hotseat items and an empty page).             
2537                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2538             }                                                                                            
2539             final int currentScreen = currScreen;                                                        
2540             final long currentScreenId = currentScreen < 0                                               
2541                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2542                                                                                                          
2543             // Load all the items that are on the current page first (and in the process, unbind         
2544             // all the existing workspace items before we call startBinding() below.                     
2545             unbindWorkspaceItemsOnMainThread();                                                          
2546                                                                                                          
2547             // Separate the items that are on the current screen, and all the other remaining items      
2548             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2549             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2550             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2551                     new ArrayList<LauncherAppWidgetInfo>();                                              
2552             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2553                     new ArrayList<LauncherAppWidgetInfo>();                                              
2554             HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                  
2555             HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                    
2556                                                                                                          
2557             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2558                     otherWorkspaceItems);                                                                
2559             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2560                     otherAppWidgets);                                                                    
2561             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2562                     otherFolders);                                                                       
2563             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2564             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2565                                                                                                          
2566             // Tell the workspace that we're about to start binding items                                
2567             r = new Runnable() {                                                                         
2568                 public void run() {                                                                      
2569                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2570                     if (callbacks != null) {                                                             
2571                         callbacks.startBinding();                                                        
2572                     }                                                                                    
2573                 }                                                                                        
2574             };                                                                                           
2575             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2576                                                                                                          
2577             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2578                                                                                                          
2579             // Load items on the current page                                                            
2580             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2581                     currentFolders, null);                                                               
2582             if (isLoadingSynchronously) {                                                                
2583                 r = new Runnable() {                                                                     
2584                     public void run() {                                                                  
2585                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2586                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2587                             callbacks.onPageBoundSynchronously(currentScreen);                           
2588                         }                                                                                
2589                     }                                                                                    
2590                 };                                                                                       
2591                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2592             }                                                                                            
2593                                                                                                          
2594             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2595             // work until after the first render)                                                        
2596             synchronized (mDeferredBindRunnables) {                                                      
2597                 mDeferredBindRunnables.clear();                                                          
2598             }                                                                                            
2599             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2600                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2601                                                                                                          
2602             // Tell the workspace that we're done binding items                                          
2603             r = new Runnable() {                                                                         
2604                 public void run() {                                                                      
2605                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2606                     if (callbacks != null) {                                                             
2607                         callbacks.finishBindingItems();                                                  
2608                     }                                                                                    
2609                                                                                                          
2610                     // If we're profiling, ensure this is the last thing in the queue.                   
2611                     if (DEBUG_LOADERS) {                                                                 
2612                         Log.d(TAG, "bound workspace in "                                                 
2613                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2614                     }                                                                                    
2615                                                                                                          
2616                     mIsLoadingAndBindingWorkspace = false;                                               
2617                 }                                                                                        
2618             };                                                                                           
2619             if (isLoadingSynchronously) {                                                                
2620                 synchronized (mDeferredBindRunnables) {                                                  
2621                     mDeferredBindRunnables.add(r);                                                       
2622                 }                                                                                        
2623             } else {                                                                                     
2624                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2625             }                                                                                            
2626         }                                                                                                
2627                                                                                                          
2628         private void loadAndBindAllApps() {                                                              
2629             if (DEBUG_LOADERS) {                                                                         
2630                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2631             }                                                                                            
2632             if (!mAllAppsLoaded) {                                                                       
2633                 loadAllApps();                                                                           
2634                 synchronized (LoaderTask.this) {                                                         
2635                     if (mStopped) {                                                                      
2636                         return;                                                                          
2637                     }                                                                                    
2638                     mAllAppsLoaded = true;                                                               
2639                 }                                                                                        
2640             } else {                                                                                     
2641                 onlyBindAllApps();                                                                       
2642             }                                                                                            
2643         }                                                                                                
2644                                                                                                          
2645         private void onlyBindAllApps() {                                                                 
2646             final Callbacks oldCallbacks = mCallbacks.get();                                             
2647             if (oldCallbacks == null) {                                                                  
2648                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2649                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2650                 return;                                                                                  
2651             }                                                                                            
2652                                                                                                          
2653             // shallow copy                                                                              
2654             @SuppressWarnings("unchecked")                                                               
2655             final ArrayList<AppInfo> list                                                                
2656                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2657             Runnable r = new Runnable() {                                                                
2658                 public void run() {                                                                      
2659                     final long t = SystemClock.uptimeMillis();                                           
2660                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2661                     if (callbacks != null) {                                                             
2662                         callbacks.bindAllApplications(list);                                             
2663                     }                                                                                    
2664                     if (DEBUG_LOADERS) {                                                                 
2665                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2666                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2667                     }                                                                                    
2668                 }                                                                                        
2669             };                                                                                           
2670             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2671             if (isRunningOnMainThread) {                                                                 
2672                 r.run();                                                                                 
2673             } else {                                                                                     
2674                 mHandler.post(r);                                                                        
2675             }                                                                                            
2676         }                                                                                                
2677                                                                                                          
2678         private void loadAllApps() {                                                                     
2679             final long loadTime = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                      
2680             final Callbacks oldCallbacks = mCallbacks.get();                                             
2681             if (oldCallbacks == null) {                                                                  
2682                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2683                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2684                 return;                                                                                  
2685             }                                                                                            
2686             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                              
2687             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                            
2688             final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                      
2689             // Clear the list of apps                                                                    
2690             mBgAllAppsList.clear();                                                                      
2691             SharedPreferences prefs = mContext.getSharedPreferences(LauncherAppState.getSharedPreferences🔵
2692             for (UserHandleCompat user : profiles) {                                                     
2693                 // Query for the set of apps                                                             
2694                 final long qiaTime = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                   
2695                 List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);       
2696                 if (DEBUG_LOADERS) {                                                                     
2697                     Log.d(TAG, (("getActivityList took " + (SystemClock.uptimeMillis() - qiaTime)) + "ms 🔵
2698                     Log.d(TAG, (("getActivityList got " + apps.size()) + " apps for user ") + user);     
2699                 }                                                                                        
2700                 // Fail if we don't have any apps                                                        
2701                 // TODO: Fix this. Only fail for the current user.                                       
2702                 if ((apps == null) || apps.isEmpty()) {                                                  
2703                     return;                                                                              
2704                 }                                                                                        
2705                 // Update icon cache                                                                     
2706                 HashSet<String> updatedPackages = mIconCache.updateDBIcons(user, apps);                  
2707                 // If any package icon has changed (app was updated while launcher was dead),            
2708                 // update the corresponding shortcuts.                                                   
2709                 if (!updatedPackages.isEmpty()) {                                                        
2710                     final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();               
2711                     synchronized(sBgLock) {                                                              
2712                         for (ItemInfo info : sBgItemsIdMap.values()) {                                   
2713                             if (((info instanceof ShortcutInfo) && user.equals(info.user)) && (info.itemT🔵
2714                                 ShortcutInfo si = ((ShortcutInfo) (info));                               
2715                                 ComponentName cn = si.getTargetComponent();                              
2716                                 if ((cn != null) && updatedPackages.contains(cn.getPackageName())) {     
2717                                     si.updateIcon(mIconCache);                                           
2718                                     updates.add(si);                                                     
2719                                 }                                                                        
2720                             }                                                                            
2721                         }                                                                                
2722                     }                                                                                    
2723                     if (!updates.isEmpty()) {                                                            
2724                         final UserHandleCompat userFinal = user;                                         
2725                         mHandler.post(new Runnable() {                                                   
2726                             public void run() {                                                          
2727                                 Callbacks cb = getCallback();                                            
2728                                 if (cb != null) {                                                        
2729                                     cb.bindShortcutsChanged(updates, new ArrayList<ShortcutInfo>(), userF🔵
2730                                 }                                                                        
2731                             }                                                                            
2732                         });                                                                              
2733                     }                                                                                    
2734                 }                                                                                        
2735                 // Create the ApplicationInfos                                                           
2736                 for (int i = 0; i < apps.size(); i++) {                                                  
2737                     LauncherActivityInfoCompat app = apps.get(i);                                        
2738                     // This builds the icon bitmaps.                                                     
2739                     mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                    
2740                 }                                                                                        
2741                 if (ADD_MANAGED_PROFILE_SHORTCUTS && (!user.equals(UserHandleCompat.myUserHandle()))) {  
2742                     // Add shortcuts for packages which were installed while launcher was dead.          
2743                     String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX + mUserManager.getSerialNumbe🔵
2744                     Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET🔵
2745                     HashSet<String> newPackageSet = new HashSet<String>();                               
2746                     for (LauncherActivityInfoCompat info : apps) {                                       
2747                         String packageName = info.getComponentName().getPackageName();                   
2748                         if ((!packagesAdded.contains(packageName)) && (!newPackageSet.contains(packageNam🔵
2749                             InstallShortcutReceiver.queueInstallShortcut(info, mContext);                
2750                         }                                                                                
2751                         newPackageSet.add(packageName);                                                  
2752                     }                                                                                    
2753                     prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                  
2754                 }                                                                                        
2755             }                                                                                            
2756             // Huh? Shouldn't this be inside the Runnable below?                                         
2757             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2758             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2759             // Post callback on main thread                                                              
2760             mHandler.post(new Runnable() {                                                               
2761                 public void run() {                                                                      
2762                     final long bindTime = SystemClock.uptimeMillis();                                    
2763                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2764                     if (callbacks != null) {                                                             
2765                         callbacks.bindAllApplications(added);                                            
2766                         if (DEBUG_LOADERS) {                                                             
2767                             Log.d(TAG, ((("bound " + added.size()) + " apps in ") + (SystemClock.uptimeMi🔵
2768                         }                                                                                
2769                     } else {                                                                             
2770                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2771                     }                                                                                    
2772                 }                                                                                        
2773             });                                                                                          
2774             if (DEBUG_LOADERS) {                                                                         
2775                 Log.d(TAG, ("Icons processed in " + (SystemClock.uptimeMillis() - loadTime)) + "ms");    
2776             }                                                                                            
2777         }                                                                                                
2778                                                                                                          
2779         public void dumpState() {                                                                        
2780             synchronized (sBgLock) {                                                                     
2781                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2782                 Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                  
2783                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2784                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2785                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2786             }                                                                                            
2787         }                                                                                                
2788     }                                                                                                    
2789                                                                                                          
2790     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2791         sWorker.post(task);                                                                              
2792     }                                                                                                    
2793                                                                                                          
2794     private class AppsAvailabilityCheck extends BroadcastReceiver {                                      
2795         @Override                                                                                        
2796         public void onReceive(Context context, Intent intent) {                                          
2797             synchronized(sBgLock) {                                                                      
2798                 final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mApp.getContext())🔵
2799                 final PackageManager manager = context.getPackageManager();                              
2800                 final ArrayList<String> packagesRemoved = new ArrayList<String>();                       
2801                 final ArrayList<String> packagesUnavailable = new ArrayList<String>();                   
2802                 for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {     
2803                     UserHandleCompat user = entry.getKey();                                              
2804                     packagesRemoved.clear();                                                             
2805                     packagesUnavailable.clear();                                                         
2806                     for (String pkg : entry.getValue()) {                                                
2807                         if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                       
2808                             boolean packageOnSdcard = launcherApps.isAppEnabled(manager, pkg, PackageMana🔵
2809                             if (packageOnSdcard) {                                                       
2810                                 Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);      
2811                                 packagesUnavailable.add(pkg);                                            
2812                             } else {                                                                     
2813                                 Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);             
2814                                 packagesRemoved.add(pkg);                                                
2815                             }                                                                            
2816                         }                                                                                
2817                     }                                                                                    
2818                     if (!packagesRemoved.isEmpty()) {                                                    
2819                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE, packag🔵
2820                     }                                                                                    
2821                     if (!packagesUnavailable.isEmpty()) {                                                
2822                         enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE, p🔵
2823                     }                                                                                    
2824                 }                                                                                        
2825                 sPendingPackages.clear();                                                                
2826             }                                                                                            
2827         }                                                                                                
2828     }                                                                                                    
2829                                                                                                          
2830     private class PackageUpdatedTask implements Runnable {                                               
2831         int mOp;                                                                                         
2832                                                                                                          
2833         String[] mPackages;                                                                              
2834                                                                                                          
2835         UserHandleCompat mUser;                                                                          
2836                                                                                                          
2837         public static final int OP_NONE = 0;                                                             
2838                                                                                                          
2839         public static final int OP_ADD = 1;                                                              
2840                                                                                                          
2841         public static final int OP_UPDATE = 2;                                                           
2842                                                                                                          
2843         // uninstlled                                                                                    
2844         public static final int OP_REMOVE = 3; // uninstlled                                             
2845                                                                                                          
2846         // external media unmounted                                                                      
2847         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2848                                                                                                          
2849         public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                    
2850             mOp = op;                                                                                    
2851             mPackages = packages;                                                                        
2852             mUser = user;                                                                                
2853         }                                                                                                
2854                                                                                                          
2855         public void run() {                                                                              
2856             final Context context = mApp.getContext();                                                   
2857             final String[] packages = mPackages;                                                         
2858             final int N = packages.length;                                                               
2859             switch (mOp) {                                                                               
2860                 case OP_ADD :                                                                            
2861                     for (int i = 0; i < N; i++) {                                                        
2862                         if (DEBUG_LOADERS) {                                                             
2863                             Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                        
2864                         }                                                                                
2865                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
2866                         mBgAllAppsList.addPackage(context, packages[i], mUser);                          
2867                     }                                                                                    
2868                     // Auto add shortcuts for added packages.                                            
2869                     if (ADD_MANAGED_PROFILE_SHORTCUTS && (!UserHandleCompat.myUserHandle().equals(mUser))🔵
2870                         SharedPreferences prefs = context.getSharedPreferences(LauncherAppState.getShared🔵
2871                         String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX + mUserManager.getSerialN🔵
2872                         Set<String> shortcutSet = new HashSet<String>(prefs.getStringSet(shortcutsSetKey,🔵
2873                         for (int i = 0; i < N; i++) {                                                    
2874                             if (!shortcutSet.contains(packages[i])) {                                    
2875                                 shortcutSet.add(packages[i]);                                            
2876                                 List<LauncherActivityInfoCompat> activities = mLauncherApps.getActivityLi🔵
2877                                 if ((activities != null) && (!activities.isEmpty())) {                   
2878                                     InstallShortcutReceiver.queueInstallShortcut(activities.get(0), conte🔵
2879                                 }                                                                        
2880                             }                                                                            
2881                         }                                                                                
2882                         prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                
2883                     }                                                                                    
2884                     break;                                                                               
2885                 case OP_UPDATE :                                                                         
2886                     for (int i = 0; i < N; i++) {                                                        
2887                         if (DEBUG_LOADERS) {                                                             
2888                             Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);                     
2889                         }                                                                                
2890                         mIconCache.updateIconsForPkg(packages[i], mUser);                                
2891                         mBgAllAppsList.updatePackage(context, packages[i], mUser);                       
2892                         WidgetPreviewLoader.removePackageFromDb(mApp.getWidgetPreviewCacheDb(), packages[🔵
2893                     }                                                                                    
2894                     break;                                                                               
2895                 case OP_REMOVE :                                                                         
2896                     // Remove the packageName for the set of auto-installed shortcuts. This              
2897                     // will ensure that the shortcut when the app is installed again.                    
2898                     if (ADD_MANAGED_PROFILE_SHORTCUTS && (!UserHandleCompat.myUserHandle().equals(mUser))🔵
2899                         SharedPreferences prefs = context.getSharedPreferences(LauncherAppState.getShared🔵
2900                         String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX + mUserManager.getSerialN🔵
2901                         HashSet<String> shortcutSet = new HashSet<String>(prefs.getStringSet(shortcutsSet🔵
2902                         shortcutSet.removeAll(Arrays.asList(mPackages));                                 
2903                         prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                
2904                     }                                                                                    
2905                     for (int i = 0; i < N; i++) {                                                        
2906                         if (DEBUG_LOADERS) {                                                             
2907                             Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);                     
2908                         }                                                                                
2909                         mIconCache.removeIconsForPkg(packages[i], mUser);                                
2910                     }                                                                                    
2911                     // Fall through                                                                      
2912                 case OP_UNAVAILABLE :                                                                    
2913                     for (int i = 0; i < N; i++) {                                                        
2914                         if (DEBUG_LOADERS) {                                                             
2915                             Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);                     
2916                         }                                                                                
2917                         mBgAllAppsList.removePackage(packages[i], mUser);                                
2918                         WidgetPreviewLoader.removePackageFromDb(mApp.getWidgetPreviewCacheDb(), packages[🔵
2919                     }                                                                                    
2920                     break;                                                                               
2921             }                                                                                            
2922             ArrayList<AppInfo> added = null;                                                             
2923             ArrayList<AppInfo> modified = null;                                                          
2924             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
2925             if (mBgAllAppsList.added.size() > 0) {                                                       
2926                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
2927                 mBgAllAppsList.added.clear();                                                            
2928             }                                                                                            
2929             if (mBgAllAppsList.modified.size() > 0) {                                                    
2930                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
2931                 mBgAllAppsList.modified.clear();                                                         
2932             }                                                                                            
2933             if (mBgAllAppsList.removed.size() > 0) {                                                     
2934                 removedApps.addAll(mBgAllAppsList.removed);                                              
2935                 mBgAllAppsList.removed.clear();                                                          
2936             }                                                                                            
2937             final Callbacks callbacks = getCallback();                                                   
2938             if (callbacks == null) {                                                                     
2939                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
2940                 return;                                                                                  
2941             }                                                                                            
2942             final HashMap<ComponentName, AppInfo> addedOrUpdatedApps = new HashMap<ComponentName, AppInfo🔵
2943             if (added != null) {                                                                         
2944                 addAppsToAllApps(context, added);                                                        
2945                 for (AppInfo ai : added) {                                                               
2946                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
2947                 }                                                                                        
2948             }                                                                                            
2949             if (modified != null) {                                                                      
2950                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
2951                 for (AppInfo ai : modified) {                                                            
2952                     addedOrUpdatedApps.put(ai.componentName, ai);                                        
2953                 }                                                                                        
2954                 mHandler.post(new Runnable() {                                                           
2955                     public void run() {                                                                  
2956                         Callbacks cb = getCallback();                                                    
2957                         if ((callbacks == cb) && (cb != null)) {                                         
2958                             callbacks.bindAppsUpdated(modifiedFinal);                                    
2959                         }                                                                                
2960                     }                                                                                    
2961                 });                                                                                      
2962             }                                                                                            
2963             // Update shortcut infos                                                                     
2964             if ((mOp == OP_ADD) || (mOp == OP_UPDATE)) {                                                 
2965                 final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();          
2966                 final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();          
2967                 final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>(); 
2968                 HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));               
2969                 synchronized(sBgLock) {                                                                  
2970                     for (ItemInfo info : sBgItemsIdMap.values()) {                                       
2971                         if ((info instanceof ShortcutInfo) && mUser.equals(info.user)) {                 
2972                             ShortcutInfo si = ((ShortcutInfo) (info));                                   
2973                             boolean infoUpdated = false;                                                 
2974                             boolean shortcutUpdated = false;                                             
2975                             // Update shortcuts which use iconResource.                                  
2976                             if ((si.iconResource != null) && packageSet.contains(si.iconResource.packageN🔵
2977                                 Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName, si.🔵
2978                                 if (icon != null) {                                                      
2979                                     si.setIcon(icon);                                                    
2980                                     si.usingFallbackIcon = false;                                        
2981                                     infoUpdated = true;                                                  
2982                                 }                                                                        
2983                             }                                                                            
2984                             ComponentName cn = si.getTargetComponent();                                  
2985                             if ((cn != null) && packageSet.contains(cn.getPackageName())) {              
2986                                 AppInfo appInfo = addedOrUpdatedApps.get(cn);                            
2987                                 if (si.isPromise()) {                                                    
2988                                     if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {           
2989                                         // Auto install icon                                             
2990                                         PackageManager pm = context.getPackageManager();                 
2991                                         ResolveInfo matched = pm.resolveActivity(new Intent(Intent.ACTION🔵
2992                                         if (matched == null) {                                           
2993                                             // Try to find the best match activity.                      
2994                                             Intent intent = pm.getLaunchIntentForPackage(cn.getPackageNam🔵
2995                                             if (intent != null) {                                        
2996                                                 cn = intent.getComponent();                              
2997                                                 appInfo = addedOrUpdatedApps.get(cn);                    
2998                                             }                                                            
2999                                             if ((intent == null) || (appInfo == null)) {                 
3000                                                 removedShortcuts.add(si);                                
3001                                                 continue;                                                
3002                                             }                                                            
3003                                             si.promisedIntent = intent;                                  
3004                                         }                                                                
3005                                     }                                                                    
3006                                     // Restore the shortcut.                                             
3007                                     si.intent = si.promisedIntent;                                       
3008                                     si.promisedIntent = null;                                            
3009                                     si.status &= ((~ShortcutInfo.FLAG_RESTORED_ICON) & (~ShortcutInfo.FLA🔵
3010                                     infoUpdated = true;                                                  
3011                                     si.updateIcon(mIconCache);                                           
3012                                 }                                                                        
3013                                 if (((appInfo != null) && Intent.ACTION_MAIN.equals(si.intent.getAction()🔵
3014                                     si.updateIcon(mIconCache);                                           
3015                                     si.title = appInfo.title.toString();                                 
3016                                     si.contentDescription = appInfo.contentDescription;                  
3017                                     infoUpdated = true;                                                  
3018                                 }                                                                        
3019                                 if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {   
3020                                     // Since package was just updated, the target must be available now. 
3021                                     si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;          
3022                                     shortcutUpdated = true;                                              
3023                                 }                                                                        
3024                             }                                                                            
3025                             if (infoUpdated || shortcutUpdated) {                                        
3026                                 updatedShortcuts.add(si);                                                
3027                             }                                                                            
3028                             if (infoUpdated) {                                                           
3029                                 updateItemInDatabase(context, si);                                       
3030                             }                                                                            
3031                         } else if (info instanceof LauncherAppWidgetInfo) {                              
3032                             LauncherAppWidgetInfo widgetInfo = ((LauncherAppWidgetInfo) (info));         
3033                             if ((mUser.equals(widgetInfo.user) && widgetInfo.hasRestoreFlag(LauncherAppWi🔵
3034                                 widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READ🔵
3035                                 widgets.add(widgetInfo);                                                 
3036                                 updateItemInDatabase(context, widgetInfo);                               
3037                             }                                                                            
3038                         }                                                                                
3039                     }                                                                                    
3040                 }                                                                                        
3041                 if ((!updatedShortcuts.isEmpty()) || (!removedShortcuts.isEmpty())) {                    
3042                     mHandler.post(new Runnable() {                                                       
3043                         public void run() {                                                              
3044                             Callbacks cb = getCallback();                                                
3045                             if ((callbacks == cb) && (cb != null)) {                                     
3046                                 callbacks.bindShortcutsChanged(updatedShortcuts, removedShortcuts, mUser)🔵
3047                             }                                                                            
3048                         }                                                                                
3049                     });                                                                                  
3050                     if (!removedShortcuts.isEmpty()) {                                                   
3051                         deleteItemsFromDatabase(context, removedShortcuts);                              
3052                     }                                                                                    
3053                 }                                                                                        
3054                 if (!widgets.isEmpty()) {                                                                
3055                     mHandler.post(new Runnable() {                                                       
3056                         public void run() {                                                              
3057                             Callbacks cb = getCallback();                                                
3058                             if ((callbacks == cb) && (cb != null)) {                                     
3059                                 callbacks.bindWidgetsRestored(widgets);                                  
3060                             }                                                                            
3061                         }                                                                                
3062                     });                                                                                  
3063                 }                                                                                        
3064             }                                                                                            
3065             final ArrayList<String> removedPackageNames = new ArrayList<String>();                       
3066             if ((mOp == OP_REMOVE) || (mOp == OP_UNAVAILABLE)) {                                         
3067                 // Mark all packages in the broadcast to be removed                                      
3068                 removedPackageNames.addAll(Arrays.asList(packages));                                     
3069             } else if (mOp == OP_UPDATE) {                                                               
3070                 // Mark disabled packages in the broadcast to be removed                                 
3071                 for (int i = 0; i < N; i++) {                                                            
3072                     if (isPackageDisabled(context, packages[i], mUser)) {                                
3073                         removedPackageNames.add(packages[i]);                                            
3074                     }                                                                                    
3075                 }                                                                                        
3076             }                                                                                            
3077             if ((!removedPackageNames.isEmpty()) || (!removedApps.isEmpty())) {                          
3078                 final int removeReason;                                                                  
3079                 if (mOp == OP_UNAVAILABLE) {                                                             
3080                     removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                             
3081                 } else {                                                                                 
3082                     // Remove all the components associated with this package                            
3083                     for (String pn : removedPackageNames) {                                              
3084                         deletePackageFromDatabase(context, pn, mUser);                                   
3085                     }                                                                                    
3086                     // Remove all the specific components                                                
3087                     for (AppInfo a : removedApps) {                                                      
3088                         ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser); 
3089                         deleteItemsFromDatabase(context, infos);                                         
3090                     }                                                                                    
3091                     removeReason = 0;                                                                    
3092                 }                                                                                        
3093                 // Remove any queued items from the install queue                                        
3094                 InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);     
3095                 // Call the components-removed callback                                                  
3096                 mHandler.post(new Runnable() {                                                           
3097                     public void run() {                                                                  
3098                         Callbacks cb = getCallback();                                                    
3099                         if ((callbacks == cb) && (cb != null)) {                                         
3100                             callbacks.bindComponentsRemoved(removedPackageNames, removedApps, mUser, remo🔵
3101                         }                                                                                
3102                     }                                                                                    
3103                 });                                                                                      
3104             }                                                                                            
3105             final ArrayList<Object> widgetsAndShortcuts = getSortedWidgetsAndShortcuts(context);         
3106             mHandler.post(new Runnable() {                                                               
3107                 @Override                                                                                
3108                 public void run() {                                                                      
3109                     Callbacks cb = getCallback();                                                        
3110                     if ((callbacks == cb) && (cb != null)) {                                             
3111                         callbacks.bindPackagesUpdated(widgetsAndShortcuts);                              
3112                     }                                                                                    
3113                 }                                                                                        
3114             });                                                                                          
3115             // Write all the logs to disk                                                                
3116             mHandler.post(new Runnable() {                                                               
3117                 public void run() {                                                                      
3118                     Callbacks cb = getCallback();                                                        
3119                     if ((callbacks == cb) && (cb != null)) {                                             
3120                         callbacks.dumpLogsToLocalData();                                                 
3121                     }                                                                                    
3122                 }                                                                                        
3123             });                                                                                          
3124         }                                                                                                
3125     }                                                                                                    
3126                                                                                                          
3127     public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context) {              
3128         synchronized (sBgLock) {                                                                         
3129             if (sBgWidgetProviders != null && !sWidgetProvidersDirty) {                                  
3130                 return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());        
3131             }                                                                                            
3132             sBgWidgetProviders = new HashMap<ComponentName, LauncherAppWidgetProviderInfo>();            
3133             List<AppWidgetProviderInfo> widgets =                                                        
3134                     AppWidgetManagerCompat.getInstance(context).getAllProviders();                       
3135             LauncherAppWidgetProviderInfo info;                                                          
3136             for (AppWidgetProviderInfo pInfo : widgets) {                                                
3137                 info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                   
3138                 sBgWidgetProviders.put(info.provider, info);                                             
3139             }                                                                                            
3140                                                                                                          
3141             Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();         
3142             for (CustomAppWidget widget : customWidgets) {                                               
3143                 info = new LauncherAppWidgetProviderInfo(context, widget);                               
3144                 sBgWidgetProviders.put(info.provider, info);                                             
3145             }                                                                                            
3146             sWidgetProvidersDirty = false;                                                               
3147             return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());            
3148         }                                                                                                
3149     }                                                                                                    
3150                                                                                                          
3151     public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {       
3152         synchronized (sBgLock) {                                                                         
3153             if (sBgWidgetProviders == null) {                                                            
3154                 getWidgetProviders(ctx);                                                                 
3155             }                                                                                            
3156             return sBgWidgetProviders.get(name);                                                         
3157         }                                                                                                
3158     }                                                                                                    
3159                                                                                                          
3160     // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                     
3161     public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                      
3162         PackageManager packageManager = context.getPackageManager();                                     
3163         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3164         widgetsAndShortcuts.addAll(getWidgetProviders(context));                                         
3165         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3166         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3167         Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));             
3168         return widgetsAndShortcuts;                                                                      
3169     }                                                                                                    
3170                                                                                                          
3171     private static boolean isPackageDisabled(Context context, String packageName,                        
3172             UserHandleCompat user) {                                                                     
3173         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3174         return !launcherApps.isPackageEnabledForProfile(packageName, user);                              
3175     }                                                                                                    
3176                                                                                                          
3177     public static boolean isValidPackageActivity(Context context, ComponentName cn,                      
3178             UserHandleCompat user) {                                                                     
3179         if (cn == null) {                                                                                
3180             return false;                                                                                
3181         }                                                                                                
3182         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3183         if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                       
3184             return false;                                                                                
3185         }                                                                                                
3186         return launcherApps.isActivityEnabledForProfile(cn, user);                                       
3187     }                                                                                                    
3188                                                                                                          
3189     public static boolean isValidPackage(Context context, String packageName,                            
3190             UserHandleCompat user) {                                                                     
3191         if (packageName == null) {                                                                       
3192             return false;                                                                                
3193         }                                                                                                
3194         final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                 
3195         return launcherApps.isPackageEnabledForProfile(packageName, user);                               
3196     }                                                                                                    
3197                                                                                                          
3198     /**                                                                                                  
3199      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3200      * to a package that is not yet installed on the system.                                             
3201      */                                                                                                  
3202     public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent, int promiseType🔵
3203         final ShortcutInfo info = new ShortcutInfo();                                                    
3204         info.user = UserHandleCompat.myUserHandle();                                                     
3205         mIconCache.getTitleAndIcon(info, intent, info.user);                                             
3206         if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                      
3207             String title = (cursor != null) ? cursor.getString(titleIndex) : null;                       
3208             if (!TextUtils.isEmpty(title)) {                                                             
3209                 info.title = title;                                                                      
3210             }                                                                                            
3211             info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                               
3212         } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                             
3213             if (TextUtils.isEmpty(info.title)) {                                                         
3214                 info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                       
3215             }                                                                                            
3216             info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                             
3217         } else {                                                                                         
3218             throw new InvalidParameterException("Invalid restoreType " + promiseType);                   
3219         }                                                                                                
3220         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title.toString(), info.user);  
3221         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3222         info.promisedIntent = intent;                                                                    
3223         return info;                                                                                     
3224     }                                                                                                    
3225                                                                                                          
3226     /**                                                                                                  
3227      * Make an Intent object for a restored application or shortcut item that points                     
3228      * to the market page for the item.                                                                  
3229      */                                                                                                  
3230     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                     
3231         ComponentName componentName = intent.getComponent();                                             
3232         return getMarketIntent(componentName.getPackageName());                                          
3233     }                                                                                                    
3234                                                                                                          
3235     static Intent getMarketIntent(String packageName) {                                                  
3236         return new Intent(Intent.ACTION_VIEW)                                                            
3237             .setData(new Uri.Builder()                                                                   
3238                 .scheme("market")                                                                        
3239                 .authority("details")                                                                    
3240                 .appendQueryParameter("id", packageName)                                                 
3241                 .build());                                                                               
3242     }                                                                                                    
3243                                                                                                          
3244     /**                                                                                                  
3245      * Make an ShortcutInfo object for a shortcut that is an application.                                
3246      *                                                                                                   
3247      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3248      */                                                                                                  
3249     public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent, UserHandleCompat user, 🔵
3250         if (user == null) {                                                                              
3251             Log.d(TAG, "Null user found in getShortcutInfo");                                            
3252             return null;                                                                                 
3253         }                                                                                                
3254         ComponentName componentName = intent.getComponent();                                             
3255         if (componentName == null) {                                                                     
3256             Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                  
3257             return null;                                                                                 
3258         }                                                                                                
3259         Intent newIntent = new Intent(intent.getAction(), null);                                         
3260         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3261         newIntent.setComponent(componentName);                                                           
3262         LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                 
3263         if ((lai == null) && (!allowMissingTarget)) {                                                    
3264             Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                   
3265             return null;                                                                                 
3266         }                                                                                                
3267         final ShortcutInfo info = new ShortcutInfo();                                                    
3268         mIconCache.getTitleAndIcon(info, componentName, lai, user, false);                               
3269         if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && (c != null)) {                   
3270             Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                             
3271             info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                         
3272         }                                                                                                
3273         // from the db                                                                                   
3274         if (TextUtils.isEmpty(info.title) && (c != null)) {                                              
3275             info.title = c.getString(titleIndex);                                                        
3276         }                                                                                                
3277         // fall back to the class name of the activity                                                   
3278         if (info.title == null) {                                                                        
3279             info.title = componentName.getClassName();                                                   
3280         }                                                                                                
3281         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3282         info.user = user;                                                                                
3283         info.contentDescription = mUserManager.getBadgedLabelForUser(info.title.toString(), info.user);  
3284         return info;                                                                                     
3285     }                                                                                                    
3286                                                                                                          
3287     static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                               
3288             ItemInfoFilter f) {                                                                          
3289         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3290         for (ItemInfo i : infos) {                                                                       
3291             if (i instanceof ShortcutInfo) {                                                             
3292                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3293                 ComponentName cn = info.getTargetComponent();                                            
3294                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3295                     filtered.add(info);                                                                  
3296                 }                                                                                        
3297             } else if (i instanceof FolderInfo) {                                                        
3298                 FolderInfo info = (FolderInfo) i;                                                        
3299                 for (ShortcutInfo s : info.contents) {                                                   
3300                     ComponentName cn = s.getTargetComponent();                                           
3301                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3302                         filtered.add(s);                                                                 
3303                     }                                                                                    
3304                 }                                                                                        
3305             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3306                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3307                 ComponentName cn = info.providerName;                                                    
3308                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3309                     filtered.add(info);                                                                  
3310                 }                                                                                        
3311             }                                                                                            
3312         }                                                                                                
3313         return new ArrayList<ItemInfo>(filtered);                                                        
3314     }                                                                                                    
3315                                                                                                          
3316     private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                   
3317             final UserHandleCompat user) {                                                               
3318         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3319             @Override                                                                                    
3320             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3321                 if (info.user == null) {                                                                 
3322                     return cn.equals(cname);                                                             
3323                 } else {                                                                                 
3324                     return cn.equals(cname) && info.user.equals(user);                                   
3325                 }                                                                                        
3326             }                                                                                            
3327         };                                                                                               
3328         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3329     }                                                                                                    
3330                                                                                                          
3331     /**                                                                                                  
3332      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3333      */                                                                                                  
3334     private ShortcutInfo getShortcutInfo(Cursor c, Context context, int iconTypeIndex, int iconPackageInd🔵
3335         Bitmap icon = null;                                                                              
3336         final ShortcutInfo info = new ShortcutInfo();                                                    
3337         // Non-app shortcuts are only supported for current user.                                        
3338         info.user = UserHandleCompat.myUserHandle();                                                     
3339         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3340         // TODO: If there's an explicit component and we can't install that, delete it.                  
3341         info.title = c.getString(titleIndex);                                                            
3342         int iconType = c.getInt(iconTypeIndex);                                                          
3343         switch (iconType) {                                                                              
3344             case LauncherSettings.Favorites.ICON_TYPE_RESOURCE :                                         
3345                 String packageName = c.getString(iconPackageIndex);                                      
3346                 String resourceName = c.getString(iconResourceIndex);                                    
3347                 info.customIcon = false;                                                                 
3348                 // the resource                                                                          
3349                 icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);       
3350             // the db                                                                                    
3351                 if (icon == null) {                                                                      
3352                     icon = Utilities.createIconBitmap(c, iconIndex, context);                            
3353                 }                                                                                        
3354                 // the fallback icon                                                                     
3355                 if (icon == null) {                                                                      
3356                     icon = mIconCache.getDefaultIcon(info.user);                                         
3357                     info.usingFallbackIcon = true;                                                       
3358                 }                                                                                        
3359                 break;                                                                                   
3360             case LauncherSettings.Favorites.ICON_TYPE_BITMAP :                                           
3361                 icon = Utilities.createIconBitmap(c, iconIndex, context);                                
3362                 if (icon == null) {                                                                      
3363                     icon = mIconCache.getDefaultIcon(info.user);                                         
3364                     info.customIcon = false;                                                             
3365                     info.usingFallbackIcon = true;                                                       
3366                 } else {                                                                                 
3367                     info.customIcon = true;                                                              
3368                 }                                                                                        
3369                 break;                                                                                   
3370             default :                                                                                    
3371                 icon = mIconCache.getDefaultIcon(info.user);                                             
3372                 info.usingFallbackIcon = true;                                                           
3373                 info.customIcon = false;                                                                 
3374                 break;                                                                                   
3375         }                                                                                                
3376         info.setIcon(icon);                                                                              
3377         return info;                                                                                     
3378     }                                                                                                    
3379                                                                                                          
3380     ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                  
3381         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3382         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3383         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3384                                                                                                          
3385         if (intent == null) {                                                                            
3386             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3387             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3388             return null;                                                                                 
3389         }                                                                                                
3390                                                                                                          
3391         Bitmap icon = null;                                                                              
3392         boolean customIcon = false;                                                                      
3393         ShortcutIconResource iconResource = null;                                                        
3394                                                                                                          
3395         if (bitmap instanceof Bitmap) {                                                                  
3396             icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                 
3397             customIcon = true;                                                                           
3398         } else {                                                                                         
3399             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3400             if (extra instanceof ShortcutIconResource) {                                                 
3401                 iconResource = (ShortcutIconResource) extra;                                             
3402                 icon = Utilities.createIconBitmap(iconResource.packageName,                              
3403                         iconResource.resourceName, mIconCache, context);                                 
3404             }                                                                                            
3405         }                                                                                                
3406                                                                                                          
3407         final ShortcutInfo info = new ShortcutInfo();                                                    
3408                                                                                                          
3409         // Only support intents for current user for now. Intents sent from other                        
3410         // users wouldn't get here without intent forwarding anyway.                                     
3411         info.user = UserHandleCompat.myUserHandle();                                                     
3412         if (icon == null) {                                                                              
3413             icon = mIconCache.getDefaultIcon(info.user);                                                 
3414             info.usingFallbackIcon = true;                                                               
3415         }                                                                                                
3416         info.setIcon(icon);                                                                              
3417                                                                                                          
3418         info.title = name;                                                                               
3419         info.contentDescription = mUserManager.getBadgedLabelForUser(                                    
3420                 info.title.toString(), info.user);                                                       
3421         info.intent = intent;                                                                            
3422         info.customIcon = customIcon;                                                                    
3423         info.iconResource = iconResource;                                                                
3424                                                                                                          
3425         return info;                                                                                     
3426     }                                                                                                    
3427                                                                                                          
3428     /**                                                                                                  
3429      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3430      * or make a new one.                                                                                
3431      */                                                                                                  
3432     private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {             
3433         // See if a placeholder was created for us already                                               
3434         FolderInfo folderInfo = folders.get(id);                                                         
3435         if (folderInfo == null) {                                                                        
3436             // No placeholder -- create a new instance                                                   
3437             folderInfo = new FolderInfo();                                                               
3438             folders.put(id, folderInfo);                                                                 
3439         }                                                                                                
3440         return folderInfo;                                                                               
3441     }                                                                                                    
3442                                                                                                          
3443     public static final Comparator<AppInfo> getAppNameComparator() {                                     
3444         final Collator collator = Collator.getInstance();                                                
3445         return new Comparator<AppInfo>() {                                                               
3446             public final int compare(AppInfo a, AppInfo b) {                                             
3447                 if (a.user.equals(b.user)) {                                                             
3448                     int result = collator.compare(a.title.toString().trim(),                             
3449                             b.title.toString().trim());                                                  
3450                     if (result == 0) {                                                                   
3451                         result = a.componentName.compareTo(b.componentName);                             
3452                     }                                                                                    
3453                     return result;                                                                       
3454                 } else {                                                                                 
3455                     // TODO Need to figure out rules for sorting                                         
3456                     // profiles, this puts work second.                                                  
3457                     return a.user.toString().compareTo(b.user.toString());                               
3458                 }                                                                                        
3459             }                                                                                            
3460         };                                                                                               
3461     }                                                                                                    
3462                                                                                                          
3463     public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR = new Comparator<AppInfo>() {    
3464         public final int compare(AppInfo a, AppInfo b) {                                                 
3465             if (a.firstInstallTime < b.firstInstallTime) {                                               
3466                 return 1;                                                                                
3467             }                                                                                            
3468             if (a.firstInstallTime > b.firstInstallTime) {                                               
3469                 return -1;                                                                               
3470             }                                                                                            
3471             return 0;                                                                                    
3472         }                                                                                                
3473     };                                                                                                   
3474                                                                                                          
3475     static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                             
3476         if (info.activityInfo != null) {                                                                 
3477             return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);             
3478         } else {                                                                                         
3479             return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);               
3480         }                                                                                                
3481     }                                                                                                    
3482                                                                                                          
3483     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                  
3484         private final AppWidgetManagerCompat mManager;                                                   
3485                                                                                                          
3486         private final PackageManager mPackageManager;                                                    
3487                                                                                                          
3488         private final HashMap<Object, String> mLabelCache;                                               
3489                                                                                                          
3490         private final Collator mCollator;                                                                
3491                                                                                                          
3492         WidgetAndShortcutNameComparator(Context context) {                                               
3493             mManager = AppWidgetManagerCompat.getInstance(context);                                      
3494             mPackageManager = context.getPackageManager();                                               
3495             mLabelCache = new HashMap<Object, String>();                                                 
3496             mCollator = Collator.getInstance();                                                          
3497         }                                                                                                
3498                                                                                                          
3499         public final int compare(Object a, Object b) {                                                   
3500             String labelA;                                                                               
3501             String labelB;                                                                               
3502             if (mLabelCache.containsKey(a)) {                                                            
3503                 labelA = mLabelCache.get(a);                                                             
3504             } else {                                                                                     
3505                 labelA = (a instanceof LauncherAppWidgetProviderInfo) ? mManager.loadLabel(((LauncherAppW🔵
3506                 mLabelCache.put(a, labelA);                                                              
3507             }                                                                                            
3508             if (mLabelCache.containsKey(b)) {                                                            
3509                 labelB = mLabelCache.get(b);                                                             
3510             } else {                                                                                     
3511                 labelB = (b instanceof LauncherAppWidgetProviderInfo) ? mManager.loadLabel(((LauncherAppW🔵
3512                 mLabelCache.put(b, labelB);                                                              
3513             }                                                                                            
3514             return mCollator.compare(labelA, labelB);                                                    
3515         }                                                                                                
3516     }                                                                                                    
3517                                                                                                          
3518     static boolean isValidProvider(AppWidgetProviderInfo provider) {                                     
3519         return (provider != null) && (provider.provider != null)                                         
3520                 && (provider.provider.getPackageName() != null);                                         
3521     }                                                                                                    
3522                                                                                                          
3523     public void dumpState() {                                                                            
3524         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3525         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3526         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3527         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3528         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3529         if (mLoaderTask != null) {                                                                       
3530             mLoaderTask.dumpState();                                                                     
3531         } else {                                                                                         
3532             Log.d(TAG, "mLoaderTask=null");                                                              
3533         }                                                                                                
3534     }                                                                                                    
3535                                                                                                          
3536     public Callbacks getCallback() {                                                                     
3537         return mCallbacks != null ? mCallbacks.get() : null;                                             
3538     }                                                                                                    
3539 }                                                                                                        




































































































































































































ours vs. base theirs vs. base
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.app.SearchManager;                                                                                 
  20  import android.appwidget.AppWidgetProviderInfo;                                                                   
  21  import android.content.BroadcastReceiver;                                                                         
  22  import android.content.ComponentName;                                                                             
  23  import android.content.ContentProviderClient;                                                                     
  24  import android.content.ContentProviderOperation;                                                                  
  25  import android.content.ContentResolver;                                                                           
  26  import android.content.ContentValues;                                                                             
  27  import android.content.Context;                                                                                   
  28  import android.content.Intent;                                                                                    
  29  import android.content.Intent.ShortcutIconResource;                                                               
  30  import android.content.IntentFilter;                                                                              
  31  import android.content.SharedPreferences;                                                                         
  32  import android.content.pm.PackageManager;                                                                         
  33  import android.content.pm.ProviderInfo;                                                                           
  34  import android.content.pm.ResolveInfo;                                                                            
  35  import android.content.res.Configuration;                                                                         
  36  import android.content.res.Resources;                                                                             
  37  import android.database.Cursor;                                                                                   
  38  import android.graphics.Bitmap;                                                                                   
  39 -import android.graphics.BitmapFactory;                                                                            
  40  import android.graphics.Rect;                                                                                     
  41  import android.net.Uri;                                                                                           
  42  import android.os.Environment;                                                                                    
  43  import android.os.Handler;                                                                                        
  44  import android.os.HandlerThread;                                                                                  
  45  import android.os.Parcelable;                                                                                     
  46  import android.os.Process;                                                                                        
  47  import android.os.RemoteException;                                                                                
  48  import android.os.SystemClock;                                                                                    
  49  import android.provider.BaseColumns;                                                                              
  50  import android.text.TextUtils;                                                                                    
  51  import android.util.Log;                                                                                          
  52  import android.util.LongSparseArray;                                                                              
  53  import android.util.Pair;                                                                                         
  54                                                                                                                    
  55  import com.android.launcher3.compat.AppWidgetManagerCompat;                                                       
  56  import com.android.launcher3.compat.LauncherActivityInfoCompat;                                                   
  57  import com.android.launcher3.compat.LauncherAppsCompat;                                                           
  58  import com.android.launcher3.compat.PackageInstallerCompat;                                                       
  59  import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                                    
  60  import com.android.launcher3.compat.UserHandleCompat;                                                             
  61  import com.android.launcher3.compat.UserManagerCompat;                                                            
  62                                                                                                                    
  63  import java.lang.ref.WeakReference;                                                                               
  64  import java.net.URISyntaxException;                                                                               
  65  import java.security.InvalidParameterException;                                                                   
  66  import java.text.Collator;                                                                                        
  67  import java.util.ArrayList;                                                                                       
  68  import java.util.Arrays;                                                                                          
  69  import java.util.Collection;                                                                                      
  70  import java.util.Collections;                                                                                     
  71  import java.util.Comparator;                                                                                      
  72  import java.util.HashMap;                                                                                         
  73  import java.util.HashSet;                                                                                         
  74  import java.util.Iterator;                                                                                        
  75  import java.util.List;                                                                                            
  76  import java.util.Map.Entry;                                                                                       
  77  import java.util.Set;                                                                                             
  78                                                                                                                    
  79  /**                                                                                                               
  80   * Maintains in-memory state of the Launcher. It is expected that there should be only one                        
  81   * LauncherModel object held in a static. Also provide APIs for updating the database state                       
  82   * for the Launcher.                                                                                              
  83   */                                                                                                               
  84  public class LauncherModel extends BroadcastReceiver                                                              
  85          implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                               
  86      static final boolean DEBUG_LOADERS = false;                                                                   
  87      private static final boolean DEBUG_RECEIVER = false;                                                          
  88      private static final boolean REMOVE_UNRESTORED_ICONS = true;                                                  
  89      private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                           
  90                                                                                                                    
  91      static final String TAG = "Launcher.Model";                                                                   
  92                                                                                                                    
  93      public static final int LOADER_FLAG_NONE = 0;                                                                 
  94      public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                                 
  95      public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                               
  96                                                                                                                    
  97      private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                               
  98      private static final long INVALID_SCREEN_ID = -1L;                                                            
  99                                                                                                                    
 100      private final boolean mAppsCanBeOnRemoveableStorage;                                                          
 101      private final boolean mOldContentProviderExists;                                                              
 102                                                                                                                    
 103      private final LauncherAppState mApp;                                                                          
 104      private final Object mLock = new Object();                                                                    
 105      private DeferredHandler mHandler = new DeferredHandler();                                                     
 106      private LoaderTask mLoaderTask;                                                                               
 107      private boolean mIsLoaderTaskRunning;                                                                         
 108                                                                                                                    
 109      /**                                                                                                           
 110       * Maintain a set of packages per user, for which we added a shortcut on the workspace.                       
 111       */                                                                                                           
 112      private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";             
 113                                                                                                                    
 114      // Specific runnable types that are run on the main thread deferred handler, this allows us to                
 115      // clear all queued binding runnables when the Launcher activity is destroyed.                                
 116      private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                                     
 117      private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                                    
 118                                                                                                                    
 119      private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                             
 120                                                                                                                    
 121      private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                      
 122      static {                                                                                                      
 123          sWorkerThread.start();                                                                                    
 124      }                                                                                                             
 125      private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                
 126                                                                                                                    
 127      // We start off with everything not loaded.  After that, we assume that                                       
 128      // our monitoring of the package manager provides all updates and we never                                    
 129      // need to do a requery.  These are only ever touched from the loader thread.                                 
 130      private boolean mWorkspaceLoaded;                                                                             
 131      private boolean mAllAppsLoaded;                                                                               
 132                                                                                                                    
 133      // When we are loading pages synchronously, we can't just post the binding of items on the side               
 134      // pages as this delays the rotation process.  Instead, we wait for a callback from the first                 
 135      // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start                
 136      // a normal load, we also clear this set of Runnables.                                                        
 137      static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                          
 138                                                                                                                    
 139      private WeakReference<Callbacks> mCallbacks;                                                                  
 140                                                                                                                    
 141      // < only access in worker thread >                                                                           
 142      AllAppsList mBgAllAppsList;                                                                                   
 143                                                                                                                    
 144      // The lock that must be acquired before referencing any static bg data structures.  Unlike                   
 145      // other locks, this one can generally be held long-term because we never expect any of these                 
 146      // static data structures to be referenced outside of the worker thread except on the first                   
 147      // load after configuration change.                                                                           
 148      static final Object sBgLock = new Object();                                                                   
 149                                                                                                                    
 150      // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by                        
 151      // LauncherModel to their ids                                                                                 
 152      static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                           
 153                                                                                                                    
 154      // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts                
 155      //       created by LauncherModel that are directly on the home screen (however, no widgets or                
 156      //       shortcuts within folders).                                                                           
 157      static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                               
 158                                                                                                                    
 159      // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()             
 160      static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                                 
 161          new ArrayList<LauncherAppWidgetInfo>();                                                                   
 162                                                                                                                    
 163      // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                            
 164      static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                          
 165 -                                                                                                                  
 166 -    // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database               
 167 -    static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                          
 168                                                                                                                    
 169      // sBgWorkspaceScreens is the ordered set of workspace screens.                                               
 170      static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                                     
 171                                                                                                                    
 172      // sBgWidgetProviders is the set of widget providers including custom internal widgets                        
 173      public static HashMap<ComponentName, LauncherAppWidgetProviderInfo> sBgWidgetProviders;                       
 174      public static boolean sWidgetProvidersDirty;                                                                  
 175                                                                                                                    
 176      // sPendingPackages is a set of packages which could be on sdcard and are not available yet                   
 177      static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                                    
 178              new HashMap<UserHandleCompat, HashSet<String>>();                                                     
 179                                                                                                                    
 180      // </ only access in worker thread >                                                                          
 181                                                                                                                    
 182      private IconCache mIconCache;                                                                                 
 183                                                                                                                    
 184      protected int mPreviousConfigMcc;                                                                             
 185                                                                                                                    
 186      private final LauncherAppsCompat mLauncherApps;                                                               
 187      private final UserManagerCompat mUserManager;                                                                 
 188                                                                                                                    
 189      public interface Callbacks {                                                                                  
 190          public boolean setLoadOnResume();                                                                         
 191          public int getCurrentWorkspaceScreen();                                                                   
 192          public void startBinding();                                                                               
 193          public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                                  
 194                                boolean forceAnimateIcons);                                                         
 195          public void bindScreens(ArrayList<Long> orderedScreenIds);                                                
 196          public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                             
 197          public void bindFolders(HashMap<Long,FolderInfo> folders);                                                
 198          public void finishBindingItems();                                                                         
 199          public void bindAppWidget(LauncherAppWidgetInfo info);                                                    
 200          public void bindAllApplications(ArrayList<AppInfo> apps);                                                 
 201          public void bindAppsAdded(ArrayList<Long> newScreens,                                                     
 202                                    ArrayList<ItemInfo> addNotAnimated,                                             
 203                                    ArrayList<ItemInfo> addAnimated,                                                
 204                                    ArrayList<AppInfo> addedApps);                                                  
 205          public void bindAppsUpdated(ArrayList<AppInfo> apps);                                                     
 206          public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                         
 207                  ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                          
 208          public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                                
 209          public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);                                
 210          public void updatePackageBadge(String packageName);                                                       
 211          public void bindComponentsRemoved(ArrayList<String> packageNames,                                         
 212                          ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                          
 213          public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                                   
 214          public void bindSearchablesChanged();                                                                     
 215          public boolean isAllAppsButtonRank(int rank);                                                             
 216          public void onPageBoundSynchronously(int page);                                                           
 217          public void dumpLogsToLocalData();                                                                        
 218          public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,                    
 219                  int[] cell, int spanX, int spanY);                                                                
 220      }                                                                                                             
 221                                                                                                                    
 222      public interface ItemInfoFilter {                                                                             
 223          public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                              
 224      }                                                                                                             
 225                                                                                                                    
 226      public interface ScreenPosProvider {                                                                          
 227          int getScreenIndex(ArrayList<Long> screenIDs);                                                            
 228      }                                                                                                             
 229                                                                                                                    
 230      LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                               
 231          Context context = app.getContext();                                                                       
 232                                                                                                                    
 233          mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                                 
 234          String oldProvider = context.getString(R.string.old_launcher_provider_uri);                               
 235          // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different                        
 236          // resource string.                                                                                       
 237          String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                         
 238          ProviderInfo providerInfo =                                                                               
 239                  context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                         
 240          ProviderInfo redirectProvider =                                                                           
 241                  context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                         
 242                                                                                                                    
 243          Log.d(TAG, "Old launcher provider: " + oldProvider);                                                      
 244          mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                         
 245                                                                                                                    
 246          if (mOldContentProviderExists) {                                                                          
 247              Log.d(TAG, "Old launcher provider exists.");                                                          
 248          } else {                                                                                                  
 249              Log.d(TAG, "Old launcher provider does not exist.");                                                  
 250          }                                                                                                         
 251                                                                                                                    
 252          mApp = app;                                                                                               
 253          mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                                   
 254          mIconCache = iconCache;                                                                                   
 255                                                                                                                    
 256          final Resources res = context.getResources();                                                             
 257          Configuration config = res.getConfiguration();                                                            
 258          mPreviousConfigMcc = config.mcc;                                                                          
 259          mLauncherApps = LauncherAppsCompat.getInstance(context);                                                  
 260          mUserManager = UserManagerCompat.getInstance(context);                                                    
 261      }                                                                                                             
 262                                                                                                                    
 263      /** Runs the specified runnable immediately if called from the main thread, otherwise it is                   
 264       * posted on the main thread handler. */                                                                      
 265      private void runOnMainThread(Runnable r) {                                                                    
 266          runOnMainThread(r, 0);                                                                                    
 267      }                                                                                                             
 268      private void runOnMainThread(Runnable r, int type) {                                                          
 269          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 270              // If we are on the worker thread, post onto the main handler                                         
 271              mHandler.post(r);                                                                                     
 272          } else {                                                                                                  
 273              r.run();                                                                                              
 274          }                                                                                                         
 275      }                                                                                                             
 276                                                                                                                    
 277      /** Runs the specified runnable immediately if called from the worker thread, otherwise it is                 
 278       * posted on the worker thread handler. */                                                                    
 279      private static void runOnWorkerThread(Runnable r) {                                                           
 280          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 281              r.run();                                                                                              
 282          } else {                                                                                                  
 283              // If we are not on the worker thread, then post to the worker handler                                
 284              sWorker.post(r);                                                                                      
 285          }                                                                                                         
 286      }                                                                                                             
 287                                                                                                                    
 288      boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                                      
 289          return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                                  
 290      }                                                                                                             
 291                                                                                                                    
 292      public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                                
 293          // Process the updated package state                                                                      
 294          Runnable r = new Runnable() {                                                                             
 295              public void run() {                                                                                   
 296                  Callbacks callbacks = getCallback();                                                              
 297                  if (callbacks != null) {                                                                          
 298                      callbacks.updatePackageState(installInfo);                                                    
 299                  }                                                                                                 
 300              }                                                                                                     
 301          };                                                                                                        
 302          mHandler.post(r);                                                                                         
 303      }                                                                                                             
 304                                                                                                                    
 305      public void updatePackageBadge(final String packageName) {                                                    
 306          // Process the updated package badge                                                                      
 307          Runnable r = new Runnable() {                                                                             
 308              public void run() {                                                                                   
 309                  Callbacks callbacks = getCallback();                                                              
 310                  if (callbacks != null) {                                                                          
 311                      callbacks.updatePackageBadge(packageName);                                                    
 312                  }                                                                                                 
 313              }                                                                                                     
 314          };                                                                                                        
 315          mHandler.post(r);                                                                                         
 316      }                                                                                                             
 317                                                                                                                    
 318      public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                       
 319          final Callbacks callbacks = getCallback();                                                                
 320                                                                                                                    
 321          if (allAppsApps == null) {                                                                                
 322              throw new RuntimeException("allAppsApps must not be null");                                           
 323          }                                                                                                         
 324          if (allAppsApps.isEmpty()) {                                                                              
 325              return;                                                                                               
 326          }                                                                                                         
 327                                                                                                                    
 328          // Process the newly added applications and add them to the database first                                
 329          Runnable r = new Runnable() {                                                                             
 330              public void run() {                                                                                   
 331                  runOnMainThread(new Runnable() {                                                                  
 332                      public void run() {                                                                           
 333                          Callbacks cb = getCallback();                                                             
 334                          if (callbacks == cb && cb != null) {                                                      
 335                              callbacks.bindAppsAdded(null, null, null, allAppsApps);                               
 336                          }                                                                                         
 337                      }                                                                                             
 338                  });                                                                                               
 339              }                                                                                                     
 340          };                                                                                                        
 341          runOnWorkerThread(r);                                                                                     
 342      }                                                                                                             
 343                                                                                                                    
 344      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 345              final ArrayList<ItemInfo> workspaceApps) {                                                            
 346          addAndBindAddedWorkspaceApps(context, workspaceApps,                                                      
 347                  new ScreenPosProvider() {                                                                         
 348                                                                                                                    
 349                      @Override                                                                                     
 350                      public int getScreenIndex(ArrayList<Long> screenIDs) {                                        
 351                          return screenIDs.isEmpty() ? 0 : 1;                                                       
 352                      }                                                                                             
 353                  }, 1, false);                                                                                     
 354      }                                                                                                             
 355                                                                                                                    
 356      private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,                        
 357              int[] xy, int spanX, int spanY) {                                                                     
 358          LauncherAppState app = LauncherAppState.getInstance();                                                    
 359          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 360          final int xCount = (int) grid.numColumns;                                                                 
 361          final int yCount = (int) grid.numRows;                                                                    
 362          boolean[][] occupied = new boolean[xCount][yCount];                                                       
 363          if (occupiedPos != null) {                                                                                
 364              for (Rect r : occupiedPos) {                                                                          
 365                  for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                                  
 366                      for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                              
 367                          occupied[x][y] = true;                                                                    
 368                      }                                                                                             
 369                  }                                                                                                 
 370              }                                                                                                     
 371          }                                                                                                         
 372          return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                             
 373      }                                                                                                             
 374                                                                                                                    
 375      /**                                                                                                           
 376       * Find a position on the screen for the given size or adds a new screen.                                     
 377       * @return screenId and the coordinates for the item.                                                         
 378       */                                                                                                           
 379      private static Pair<Long, int[]> findSpaceForItem(                                                            
 380              Context context,                                                                                      
 381              ScreenPosProvider preferredScreen,                                                                    
 382              int fallbackStartScreen,                                                                              
 383              ArrayList<Long> workspaceScreens,                                                                     
 384              ArrayList<Long> addedWorkspaceScreensFinal,                                                           
 385              int spanX, int spanY) {                                                                               
 386          // Load position of items which are on the desktop. We can't use sBgItemsIdMap because                    
 387          // loadWorkspace() may not have been called.                                                              
 388          final ContentResolver cr = context.getContentResolver();                                                  
 389          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 390                  new String[] {                                                                                    
 391                      LauncherSettings.Favorites.SCREEN,                                                            
 392                      LauncherSettings.Favorites.CELLX,                                                             
 393                      LauncherSettings.Favorites.CELLY,                                                             
 394                      LauncherSettings.Favorites.SPANX,                                                             
 395                      LauncherSettings.Favorites.SPANY,                                                             
 396                      LauncherSettings.Favorites.CONTAINER                                                          
 397                   },                                                                                               
 398                   "container=?",                                                                                   
 399                   new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },                 
 400                   null);                                                                                           
 401                                                                                                                    
 402          final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);                       
 403          final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                         
 404          final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                         
 405          final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                         
 406          final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                         
 407          LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();                    
 408          try {                                                                                                     
 409              while (c.moveToNext()) {                                                                              
 410                  Rect rect = new Rect();                                                                           
 411                  rect.left = c.getInt(cellXIndex);                                                                 
 412                  rect.top = c.getInt(cellYIndex);                                                                  
 413                  rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                                       
 414                  rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                                       
 415                                                                                                                    
 416                  long screenId = c.getInt(screenIndex);                                                            
 417                  ArrayList<Rect> items = screenItems.get(screenId);                                                
 418                  if (items == null) {                                                                              
 419                      items = new ArrayList<Rect>();                                                                
 420                      screenItems.put(screenId, items);                                                             
 421                  }                                                                                                 
 422                  items.add(rect);                                                                                  
 423              }                                                                                                     
 424          } catch (Exception e) {                                                                                   
 425              screenItems.clear();                                                                                  
 426          } finally {                                                                                               
 427              c.close();                                                                                            
 428          }                                                                                                         
 429                                                                                                                    
 430          // Find appropriate space for the item.                                                                   
 431          long screenId = 0;                                                                                        
 432          int[] cordinates = new int[2];                                                                            
 433          boolean found = false;                                                                                    
 434                                                                                                                    
 435          int screenCount = workspaceScreens.size();                                                                
 436          // First check the preferred screen.                                                                      
 437          int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                              
 438          if (preferredScreenIndex < screenCount) {                                                                 
 439              screenId = workspaceScreens.get(preferredScreenIndex);                                                
 440              found = findNextAvailableIconSpaceInScreen(                                                           
 441                      screenItems.get(screenId), cordinates, spanX, spanY);                                         
 442          }                                                                                                         
 443                                                                                                                    
 444          if (!found) {                                                                                             
 445              // Search on any of the screens.                                                                      
 446              for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                              
 447                  screenId = workspaceScreens.get(screen);                                                          
 448                  if (findNextAvailableIconSpaceInScreen(                                                           
 449                          screenItems.get(screenId), cordinates, spanX, spanY)) {                                   
 450                      // We found a space for it                                                                    
 451                      found = true;                                                                                 
 452                      break;                                                                                        
 453                  }                                                                                                 
 454              }                                                                                                     
 455          }                                                                                                         
 456                                                                                                                    
 457          if (!found) {                                                                                             
 458              // Still no position found. Add a new screen to the end.                                              
 459              screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                              
 460                                                                                                                    
 461              // Save the screen id for binding in the workspace                                                    
 462              workspaceScreens.add(screenId);                                                                       
 463              addedWorkspaceScreensFinal.add(screenId);                                                             
 464                                                                                                                    
 465              // If we still can't find an empty space, then God help us all!!!                                     
 466              if (!findNextAvailableIconSpaceInScreen(                                                              
 467                      screenItems.get(screenId), cordinates, spanX, spanY)) {                                       
 468                  throw new RuntimeException("Can't find space to add the item");                                   
 469              }                                                                                                     
 470          }                                                                                                         
 471          return Pair.create(screenId, cordinates);                                                                 
 472      }                                                                                                             
 473                                                                                                                    
 474      /**                                                                                                           
 475       * Adds the provided items to the workspace.                                                                  
 476       * @param preferredScreen the screen where we should try to add the app first                                 
 477       * @param fallbackStartScreen the screen to start search for empty space if                                   
 478       * preferredScreen is not available.                                                                          
 479       */                                                                                                           
 480      public void addAndBindPendingItem(                                                                            
 481              final Context context,                                                                                
 482              final PendingAddItemInfo addInfo,                                                                     
 483              final ScreenPosProvider preferredScreen,                                                              
 484              final int fallbackStartScreen) {                                                                      
 485          final Callbacks callbacks = getCallback();                                                                
 486          // Process the newly added applications and add them to the database first                                
 487          Runnable r = new Runnable() {                                                                             
 488              public void run() {                                                                                   
 489                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 490                  ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                               
 491                                                                                                                    
 492                  // Find appropriate space for the item.                                                           
 493                  Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                             
 494                          fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                        
 495                          addInfo.spanX,                                                                            
 496                          addInfo.spanY);                                                                           
 497                  final long screenId = coords.first;                                                               
 498                  final int[] cordinates = coords.second;                                                           
 499                                                                                                                    
 500                  // Update the workspace screens                                                                   
 501                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 502                  runOnMainThread(new Runnable() {                                                                  
 503                      public void run() {                                                                           
 504                          Callbacks cb = getCallback();                                                             
 505                          if (callbacks == cb && cb != null) {                                                      
 506                              cb.bindAddScreens(addedWorkspaceScreensFinal);                                        
 507                              cb.bindAddPendingItem(addInfo,                                                        
 508                                      LauncherSettings.Favorites.CONTAINER_DESKTOP,                                 
 509                                      screenId, cordinates, addInfo.spanX, addInfo.spanY);                          
 510                          }                                                                                         
 511                      }                                                                                             
 512                  });                                                                                               
 513              }                                                                                                     
 514          };                                                                                                        
 515          runOnWorkerThread(r);                                                                                     
 516      }                                                                                                             
 517                                                                                                                    
 518      /**                                                                                                           
 519       * Adds the provided items to the workspace.                                                                  
 520       * @param preferredScreen the screen where we should try to add the app first                                 
 521       * @param fallbackStartScreen the screen to start search for empty space if                                   
 522       * preferredScreen is not available.                                                                          
 523       */                                                                                                           
 524      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 525              final ArrayList<ItemInfo> workspaceApps,                                                              
 526              final ScreenPosProvider preferredScreen,                                                              
 527              final int fallbackStartScreen,                                                                        
 528              final boolean allowDuplicate) {                                                                       
 529          final Callbacks callbacks = getCallback();                                                                
 530          if (workspaceApps.isEmpty()) {                                                                            
 531              return;                                                                                               
 532          }                                                                                                         
 533          // Process the newly added applications and add them to the database first                                
 534          Runnable r = new Runnable() {                                                                             
 535              public void run() {                                                                                   
 536                  final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();                        
 537                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 538                                                                                                                    
 539                  // Get the list of workspace screens.  We need to append to this list and                         
 540                  // can not use sBgWorkspaceScreens because loadWorkspace() may not have been                      
 541                  // called.                                                                                        
 542                  ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                               
 543                  synchronized(sBgLock) {                                                                           
 544                      for (ItemInfo item : workspaceApps) {                                                         
 545                          if (!allowDuplicate) {                                                                    
 546                              // Short-circuit this logic if the icon exists somewhere on the workspace             
 547                              if (shortcutExists(context, item.title.toString(),                                    
 548                                      item.getIntent(), item.user)) {                                               
 549                                  continue;                                                                         
 550                              }                                                                                     
 551                          }                                                                                         
 552                                                                                                                    
 553                          // Find appropriate space for the item.                                                   
 554                          Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                     
 555                                  fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                
 556                                  1, 1);                                                                            
 557                          long screenId = coords.first;                                                             
 558                          int[] cordinates = coords.second;                                                         
 559                                                                                                                    
 560                          ShortcutInfo shortcutInfo;                                                                
 561                          if (item instanceof ShortcutInfo) {                                                       
 562                              shortcutInfo = (ShortcutInfo) item;                                                   
 563                          } else if (item instanceof AppInfo) {                                                     
 564                              shortcutInfo = ((AppInfo) item).makeShortcut();                                       
 565                          } else {                                                                                  
 566                              throw new RuntimeException("Unexpected info type");                                   
 567                          }                                                                                         
 568                                                                                                                    
 569                          // Add the shortcut to the db                                                             
 570                          addItemToDatabase(context, shortcutInfo,                                                  
 571                                  LauncherSettings.Favorites.CONTAINER_DESKTOP,                                     
 572                                  screenId, cordinates[0], cordinates[1], false);                                   
 573                          // Save the ShortcutInfo for binding in the workspace                                     
 574                          addedShortcutsFinal.add(shortcutInfo);                                                    
 575                      }                                                                                             
 576                  }                                                                                                 
 577                                                                                                                    
 578                  // Update the workspace screens                                                                   
 579                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 580                                                                                                                    
 581                  if (!addedShortcutsFinal.isEmpty()) {                                                             
 582                      runOnMainThread(new Runnable() {                                                              
 583                          public void run() {                                                                       
 584                              Callbacks cb = getCallback();                                                         
 585                              if (callbacks == cb && cb != null) {                                                  
 586                                  final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();                
 587                                  final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();             
 588                                  if (!addedShortcutsFinal.isEmpty()) {                                             
 589                                      ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);      
 590                                      long lastScreenId = info.screenId;                                            
 591                                      for (ItemInfo i : addedShortcutsFinal) {                                      
 592                                          if (i.screenId == lastScreenId) {                                         
 593                                              addAnimated.add(i);                                                   
 594                                          } else {                                                                  
 595                                              addNotAnimated.add(i);                                                
 596                                          }                                                                         
 597                                      }                                                                             
 598                                  }                                                                                 
 599                                  callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                               
 600                                          addNotAnimated, addAnimated, null);                                       
 601                              }                                                                                     
 602                          }                                                                                         
 603                      });                                                                                           
 604                  }                                                                                                 
 605              }                                                                                                     
 606          };                                                                                                        
 607          runOnWorkerThread(r);                                                                                     
 608      }                                                                                                             
 609                                                                                                                    
 610      public void unbindItemInfosAndClearQueuedBindRunnables() {                                                    
 611          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 612              throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +              
 613                      "main thread");                                                                               
 614          }                                                                                                         
 615                                                                                                                    
 616          // Clear any deferred bind runnables                                                                      
 617          synchronized (mDeferredBindRunnables) {                                                                   
 618              mDeferredBindRunnables.clear();                                                                       
 619          }                                                                                                         
 620          // Remove any queued bind runnables                                                                       
 621          mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                          
 622          // Unbind all the workspace items                                                                         
 623          unbindWorkspaceItemsOnMainThread();                                                                       
 624      }                                                                                                             
 625                                                                                                                    
 626      /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                                 
 627      void unbindWorkspaceItemsOnMainThread() {                                                                     
 628          // Ensure that we don't use the same workspace items data structure on the main thread                    
 629          // by making a copy of workspace items first.                                                             
 630          final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                                  
 631          final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                                      
 632          synchronized (sBgLock) {                                                                                  
 633              tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                          
 634              tmpAppWidgets.addAll(sBgAppWidgets);                                                                  
 635          }                                                                                                         
 636          Runnable r = new Runnable() {                                                                             
 637                  @Override                                                                                         
 638                  public void run() {                                                                               
 639                     for (ItemInfo item : tmpWorkspaceItems) {                                                      
 640                         item.unbind();                                                                             
 641                     }                                                                                              
 642                     for (ItemInfo item : tmpAppWidgets) {                                                          
 643                         item.unbind();                                                                             
 644                     }                                                                                              
 645                  }                                                                                                 
 646              };                                                                                                    
 647          runOnMainThread(r);                                                                                       
 648      }                                                                                                             
 649                                                                                                                    
 650      /**                                                                                                           
 651       * Adds an item to the DB if it was not created previously, or move it to a new                               
 652       * <container, screen, cellX, cellY>                                                                          
 653       */                                                                                                           
 654      static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                           
 655              long screenId, int cellX, int cellY) {                                                                
 656          if (item.container == ItemInfo.NO_ID) {                                                                   
 657              // From all apps                                                                                      
 658              addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                           
 659          } else {                                                                                                  
 660              // From somewhere else                                                                                
 661              moveItemInDatabase(context, item, container, screenId, cellX, cellY);                                 
 662          }                                                                                                         
 663      }                                                                                                             
 664                                                                                                                    
 665      static void checkItemInfoLocked(                                                                              
 666              final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                             
 667          ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                           
 668          if (modelItem != null && item != modelItem) {                                                             
 669              // check all the data is consistent                                                                   
 670              if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                              
 671                  ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                            
 672                  ShortcutInfo shortcut = (ShortcutInfo) item;                                                      
 673                  if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                           
 674                          modelShortcut.intent.filterEquals(shortcut.intent) &&                                     
 675                          modelShortcut.id == shortcut.id &&                                                        
 676                          modelShortcut.itemType == shortcut.itemType &&                                            
 677                          modelShortcut.container == shortcut.container &&                                          
 678                          modelShortcut.screenId == shortcut.screenId &&                                            
 679                          modelShortcut.cellX == shortcut.cellX &&                                                  
 680                          modelShortcut.cellY == shortcut.cellY &&                                                  
 681                          modelShortcut.spanX == shortcut.spanX &&                                                  
 682                          modelShortcut.spanY == shortcut.spanY &&                                                  
 683                          ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                           
 684                          (modelShortcut.dropPos != null &&                                                         
 685                                  shortcut.dropPos != null &&                                                       
 686                                  modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                                
 687                          modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                                      
 688                      // For all intents and purposes, this is the same object                                      
 689                      return;                                                                                       
 690                  }                                                                                                 
 691              }                                                                                                     
 692                                                                                                                    
 693              // the modelItem needs to match up perfectly with item if our model is                                
 694              // to be consistent with the database-- for now, just require                                         
 695              // modelItem == item or the equality check above                                                      
 696              String msg = "item: " + ((item != null) ? item.toString() : "null") +                                 
 697                      "modelItem: " +                                                                               
 698                      ((modelItem != null) ? modelItem.toString() : "null") +                                       
 699                      "Error: ItemInfo passed to checkItemInfo doesn't match original";                             
 700              RuntimeException e = new RuntimeException(msg);                                                       
 701              if (stackTrace != null) {                                                                             
 702                  e.setStackTrace(stackTrace);                                                                      
 703              }                                                                                                     
 704              throw e;                                                                                              
 705          }                                                                                                         
 706      }                                                                                                             
 707                                                                                                                    
 708      static void checkItemInfo(final ItemInfo item) {                                                              
 709          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 710          final long itemId = item.id;                                                                              
 711          Runnable r = new Runnable() {                                                                             
 712              public void run() {                                                                                   
 713                  synchronized (sBgLock) {                                                                          
 714                      checkItemInfoLocked(itemId, item, stackTrace);                                                
 715                  }                                                                                                 
 716              }                                                                                                     
 717          };                                                                                                        
 718          runOnWorkerThread(r);                                                                                     
 719      }                                                                                                             
 720                                                                                                                    
 721      static void updateItemInDatabaseHelper(Context context, final ContentValues values,                           
 722              final ItemInfo item, final String callingFunction) {                                                  
 723          final long itemId = item.id;                                                                              
 724          final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                                  
 725          final ContentResolver cr = context.getContentResolver();                                                  
 726                                                                                                                    
 727          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 728          Runnable r = new Runnable() {                                                                             
 729              public void run() {                                                                                   
 730                  cr.update(uri, values, null, null);                                                               
 731                  updateItemArrays(item, itemId, stackTrace);                                                       
 732              }                                                                                                     
 733          };                                                                                                        
 734          runOnWorkerThread(r);                                                                                     
 735      }                                                                                                             
 736                                                                                                                    
 737      static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,           
 738              final ArrayList<ItemInfo> items, final String callingFunction) {                                      
 739          final ContentResolver cr = context.getContentResolver();                                                  
 740                                                                                                                    
 741          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 742          Runnable r = new Runnable() {                                                                             
 743              public void run() {                                                                                   
 744                  ArrayList<ContentProviderOperation> ops =                                                         
 745                          new ArrayList<ContentProviderOperation>();                                                
 746                  int count = items.size();                                                                         
 747                  for (int i = 0; i < count; i++) {                                                                 
 748                      ItemInfo item = items.get(i);                                                                 
 749                      final long itemId = item.id;                                                                  
 750                      final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                      
 751                      ContentValues values = valuesList.get(i);                                                     
 752                                                                                                                    
 753                      ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());                  
 754                      updateItemArrays(item, itemId, stackTrace);                                                   
 755                                                                                                                    
 756                  }                                                                                                 
 757                  try {                                                                                             
 758                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
 759                  } catch (Exception e) {                                                                           
 760                      e.printStackTrace();                                                                          
 761                  }                                                                                                 
 762              }                                                                                                     
 763          };                                                                                                        
 764          runOnWorkerThread(r);                                                                                     
 765      }                                                                                                             
 766                                                                                                                    
 767      static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {                    
 768          // Lock on mBgLock *after* the db operation                                                               
 769          synchronized (sBgLock) {                                                                                  
 770              checkItemInfoLocked(itemId, item, stackTrace);                                                        
 771                                                                                                                    
 772              if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
 773                      item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 774                  // Item is in a folder, make sure this folder exists                                              
 775                  if (!sBgFolders.containsKey(item.container)) {                                                    
 776                      // An items container is being set to a that of an item which is not in                       
 777                      // the list of Folders.                                                                       
 778                      String msg = "item: " + item + " container being set to: " +                                  
 779                              item.container + ", not in the list of folders";                                      
 780                      Log.e(TAG, msg);                                                                              
 781                  }                                                                                                 
 782              }                                                                                                     
 783                                                                                                                    
 784              // Items are added/removed from the corresponding FolderInfo elsewhere, such                          
 785              // as in Workspace.onDrop. Here, we just add/remove them from the list of items                       
 786              // that are on the desktop, as appropriate                                                            
 787              ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                       
 788              if (modelItem != null &&                                                                              
 789                      (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                       
 790                       modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {                      
 791                  switch (modelItem.itemType) {                                                                     
 792                      case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                        
 793                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
 794                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 795                          if (!sBgWorkspaceItems.contains(modelItem)) {                                             
 796                              sBgWorkspaceItems.add(modelItem);                                                     
 797                          }                                                                                         
 798                          break;                                                                                    
 799                      default:                                                                                      
 800                          break;                                                                                    
 801                  }                                                                                                 
 802              } else {                                                                                              
 803                  sBgWorkspaceItems.remove(modelItem);                                                              
 804              }                                                                                                     
 805          }                                                                                                         
 806      }                                                                                                             
 807                                                                                                                    
 808      /**                                                                                                           
 809       * Move an item in the DB to a new <container, screen, cellX, cellY>                                          
 810       */                                                                                                           
 811      static void moveItemInDatabase(Context context, final ItemInfo item, final long container,                    
 812              final long screenId, final int cellX, final int cellY) {                                              
 813          item.container = container;                                                                               
 814          item.cellX = cellX;                                                                                       
 815          item.cellY = cellY;                                                                                       
 816                                                                                                                    
 817          // We store hotseat items in canonical form which is this orientation invariant position                  
 818          // in the hotseat                                                                                         
 819          if (context instanceof Launcher && screenId < 0 &&                                                        
 820                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 821              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 822          } else {                                                                                                  
 823              item.screenId = screenId;                                                                             
 824          }                                                                                                         
 825                                                                                                                    
 826          final ContentValues values = new ContentValues();                                                         
 827          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 828          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 829          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 830          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
 831          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 832                                                                                                                    
 833          updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                                  
 834      }                                                                                                             
 835                                                                                                                    
 836      /**                                                                                                           
 837       * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the                        
 838       * cellX, cellY have already been updated on the ItemInfos.                                                   
 839       */                                                                                                           
 840      static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                             
 841              final long container, final int screen) {                                                             
 842                                                                                                                    
 843          ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                                  
 844          int count = items.size();                                                                                 
 845                                                                                                                    
 846          for (int i = 0; i < count; i++) {                                                                         
 847              ItemInfo item = items.get(i);                                                                         
 848              item.container = container;                                                                           
 849                                                                                                                    
 850              // We store hotseat items in canonical form which is this orientation invariant position              
 851              // in the hotseat                                                                                     
 852              if (context instanceof Launcher && screen < 0 &&                                                      
 853                      container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                  
 854                  item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,                   
 855                          item.cellY);                                                                              
 856              } else {                                                                                              
 857                  item.screenId = screen;                                                                           
 858              }                                                                                                     
 859                                                                                                                    
 860              final ContentValues values = new ContentValues();                                                     
 861              values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                     
 862              values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                             
 863              values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                             
 864              values.put(LauncherSettings.Favorites.RANK, item.rank);                                               
 865              values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                         
 866                                                                                                                    
 867              contentValues.add(values);                                                                            
 868          }                                                                                                         
 869          updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                         
 870      }                                                                                                             
 871                                                                                                                    
 872      /**                                                                                                           
 873       * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>                 
 874       */                                                                                                           
 875      static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,                  
 876              final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {            
 877          item.container = container;                                                                               
 878          item.cellX = cellX;                                                                                       
 879          item.cellY = cellY;                                                                                       
 880          item.spanX = spanX;                                                                                       
 881          item.spanY = spanY;                                                                                       
 882                                                                                                                    
 883          // We store hotseat items in canonical form which is this orientation invariant position                  
 884          // in the hotseat                                                                                         
 885          if (context instanceof Launcher && screenId < 0 &&                                                        
 886                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 887              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 888          } else {                                                                                                  
 889              item.screenId = screenId;                                                                             
 890          }                                                                                                         
 891                                                                                                                    
 892          final ContentValues values = new ContentValues();                                                         
 893          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 894          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 895          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 896          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
 897          values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                                 
 898          values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                                 
 899          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 900                                                                                                                    
 901          updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                                
 902      }                                                                                                             
 903                                                                                                                    
 904      /**                                                                                                           
 905       * Update an item to the database in a specified container.                                                   
 906       */                                                                                                           
 907      static void updateItemInDatabase(Context context, final ItemInfo item) {                                      
 908          final ContentValues values = new ContentValues();                                                         
 909          item.onAddToDatabase(context, values);                                                                    
 910          updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                                
 911      }                                                                                                             
 912                                                                                                                    
 913      /**                                                                                                           
 914       * Returns true if the shortcuts already exists in the database.                                              
 915       * we identify a shortcut by its title and intent.                                                            
 916       */                                                                                                           
 917      static boolean shortcutExists(Context context, String title, Intent intent,                                   
 918              UserHandleCompat user) {                                                                              
 919          final ContentResolver cr = context.getContentResolver();                                                  
 920          final Intent intentWithPkg, intentWithoutPkg;                                                             
 921                                                                                                                    
 922          if (intent.getComponent() != null) {                                                                      
 923              // If component is not null, an intent with null package will produce                                 
 924              // the same result and should also be a match.                                                        
 925              if (intent.getPackage() != null) {                                                                    
 926                  intentWithPkg = intent;                                                                           
 927                  intentWithoutPkg = new Intent(intent).setPackage(null);                                           
 928              } else {                                                                                              
 929                  intentWithPkg = new Intent(intent).setPackage(                                                    
 930                          intent.getComponent().getPackageName());                                                  
 931                  intentWithoutPkg = intent;                                                                        
 932              }                                                                                                     
 933          } else {                                                                                                  
 934              intentWithPkg = intent;                                                                               
 935              intentWithoutPkg = intent;                                                                            
 936          }                                                                                                         
 937          String userSerial = Long.toString(UserManagerCompat.getInstance(context)                                  
 938                  .getSerialNumberForUser(user));                                                                   
 939          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 940              new String[] { "title", "intent", "profileId" },                                                      
 941              "title=? and (intent=? or intent=?) and profileId=?",                                                 
 942              new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },                
 943              null);                                                                                                
 944          try {                                                                                                     
 945              return c.moveToFirst();                                                                               
 946          } finally {                                                                                               
 947              c.close();                                                                                            
 948          }                                                                                                         
 949      }                                                                                                             
 950                                                                                                                    
 951      /**                                                                                                           
 952       * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.                
 953       */                                                                                                           
 954      FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {                     
 955          final ContentResolver cr = context.getContentResolver();                                                  
 956          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                         
 957                  "_id=? and (itemType=? or itemType=?)",                                                           
 958                  new String[] { String.valueOf(id),                                                                
 959                          String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);                      
 960                                                                                                                    
 961          try {                                                                                                     
 962              if (c.moveToFirst()) {                                                                                
 963                  final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);          
 964                  final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);                 
 965                  final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);         
 966                  final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);               
 967                  final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                 
 968                  final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                 
 969                                                                                                                    
 970                  FolderInfo folderInfo = null;                                                                     
 971                  switch (c.getInt(itemTypeIndex)) {                                                                
 972                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 973                          folderInfo = findOrMakeFolder(folderList, id);                                            
 974                          break;                                                                                    
 975                  }                                                                                                 
 976                                                                                                                    
 977                  folderInfo.title = c.getString(titleIndex);                                                       
 978                  folderInfo.id = id;                                                                               
 979                  folderInfo.container = c.getInt(containerIndex);                                                  
 980                  folderInfo.screenId = c.getInt(screenIndex);                                                      
 981                  folderInfo.cellX = c.getInt(cellXIndex);                                                          
 982                  folderInfo.cellY = c.getInt(cellYIndex);                                                          
 983                                                                                                                    
 984                  return folderInfo;                                                                                
 985              }                                                                                                     
 986          } finally {                                                                                               
 987              c.close();                                                                                            
 988          }                                                                                                         
 989                                                                                                                    
 990          return null;                                                                                              
 991      }                                                                                                             
 992                                                                                                                    
 993      /**                                                                                                           
 994       * Add an item to the database in a specified container. Sets the container, screen, cellX and                
 995       * cellY fields of the item. Also assigns an ID to the item.                                                  
 996       */                                                                                                           
 997      static void addItemToDatabase(Context context, final ItemInfo item, final long container,                     
 998              final long screenId, final int cellX, final int cellY, final boolean notify) {                        
 999          item.container = container;                                                                               
1000          item.cellX = cellX;                                                                                       
1001          item.cellY = cellY;                                                                                       
1002          // We store hotseat items in canonical form which is this orientation invariant position                  
1003          // in the hotseat                                                                                         
1004          if (context instanceof Launcher && screenId < 0 &&                                                        
1005                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
1006              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
1007          } else {                                                                                                  
1008              item.screenId = screenId;                                                                             
1009          }                                                                                                         
1010                                                                                                                    
1011          final ContentValues values = new ContentValues();                                                         
1012          final ContentResolver cr = context.getContentResolver();                                                  
1013          item.onAddToDatabase(context, values);                                                                    
1014                                                                                                                    
1015          item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                                     
1016          values.put(LauncherSettings.Favorites._ID, item.id);                                                      
1017                                                                                                                    
1018          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
1019          Runnable r = new Runnable() {                                                                             
1020              public void run() {                                                                                   
1021                  cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                                       
1022                          LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                          
1023                                                                                                                    
1024                  // Lock on mBgLock *after* the db operation                                                       
1025                  synchronized (sBgLock) {                                                                          
1026                      checkItemInfoLocked(item.id, item, stackTrace);                                               
1027                      sBgItemsIdMap.put(item.id, item);                                                             
1028                      switch (item.itemType) {                                                                      
1029                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
1030                              sBgFolders.put(item.id, (FolderInfo) item);                                           
1031                              // Fall through                                                                       
1032                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
1033                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
1034                              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                 
1035                                      item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
1036                                  sBgWorkspaceItems.add(item);                                                      
1037                              } else {                                                                              
1038                                  if (!sBgFolders.containsKey(item.container)) {                                    
1039                                      // Adding an item to a folder that doesn't exist.                             
1040                                      String msg = "adding item: " + item + " to a folder that " +                  
1041                                              " doesn't exist";                                                     
1042                                      Log.e(TAG, msg);                                                              
1043                                  }                                                                                 
1044                              }                                                                                     
1045                              break;                                                                                
1046                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
1047                              sBgAppWidgets.add((LauncherAppWidgetInfo) item);                                      
1048                              break;                                                                                
1049                      }                                                                                             
1050                  }                                                                                                 
1051              }                                                                                                     
1052          };                                                                                                        
1053          runOnWorkerThread(r);                                                                                     
1054      }                                                                                                             
1055                                                                                                                    
1056      /**                                                                                                           
1057       * Creates a new unique child id, for a given cell span across all layouts.                                   
1058       */                                                                                                           
1059      static int getCellLayoutChildId(                                                                              
1060              long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {                  
1061          return (((int) container & 0xFF) << 24)                                                                   
1062                  | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);                   
1063      }                                                                                                             
1064                                                                                                                    
1065      private static ArrayList<ItemInfo> getItemsByPackageName(                                                     
1066              final String pn, final UserHandleCompat user) {                                                       
1067          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
1068              @Override                                                                                             
1069              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
1070                  return cn.getPackageName().equals(pn) && info.user.equals(user);                                  
1071              }                                                                                                     
1072          };                                                                                                        
1073          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
1074      }                                                                                                             
1075                                                                                                                    
1076      /**                                                                                                           
1077       * Removes all the items from the database corresponding to the specified package.                            
1078       */                                                                                                           
1079      static void deletePackageFromDatabase(Context context, final String pn,                                       
1080              final UserHandleCompat user) {                                                                        
1081          deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                                        
1082      }                                                                                                             
1083                                                                                                                    
1084      /**                                                                                                           
1085       * Removes the specified item from the database                                                               
1086       * @param context                                                                                             
1087       * @param item                                                                                                
1088       */                                                                                                           
1089      static void deleteItemFromDatabase(Context context, final ItemInfo item) {                                    
1090          ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                                    
1091          items.add(item);                                                                                          
1092          deleteItemsFromDatabase(context, items);                                                                  
1093      }                                                                                                             
1094                                                                                                                    
1095      /**                                                                                                           
1096       * Removes the specified items from the database                                                              
1097       * @param context                                                                                             
1098       * @param item                                                                                                
1099       */                                                                                                           
1100      static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {             
1101          final ContentResolver cr = context.getContentResolver();                                                  
1102                                                                                                                    
1103          Runnable r = new Runnable() {                                                                             
1104              public void run() {                                                                                   
1105                  for (ItemInfo item : items) {                                                                     
1106                      final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);                     
1107                      cr.delete(uri, null, null);                                                                   
1108                                                                                                                    
1109                      // Lock on mBgLock *after* the db operation                                                   
1110                      synchronized (sBgLock) {                                                                      
1111                          switch (item.itemType) {                                                                  
1112                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
1113                                  sBgFolders.remove(item.id);                                                       
1114                                  for (ItemInfo info: sBgItemsIdMap.values()) {                                     
1115                                      if (info.container == item.id) {                                              
1116                                          // We are deleting a folder which still contains items that               
1117                                          // think they are contained by that folder.                               
1118                                          String msg = "deleting a folder (" + item + ") which still " +            
1119                                                  "contains items (" + info + ")";                                  
1120                                          Log.e(TAG, msg);                                                          
1121                                      }                                                                             
1122                                  }                                                                                 
1123                                  sBgWorkspaceItems.remove(item);                                                   
1124                                  break;                                                                            
1125                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1126                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1127                                  sBgWorkspaceItems.remove(item);                                                   
1128                                  break;                                                                            
1129                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
1130                                  sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                               
1131                                  break;                                                                            
1132                          }                                                                                         
1133                          sBgItemsIdMap.remove(item.id);                                                            
1134 -                        sBgDbIconCache.remove(item);                                                              
1135                      }                                                                                             
1136                  }                                                                                                 
1137              }                                                                                                     
1138          };                                                                                                        
1139          runOnWorkerThread(r);                                                                                     
1140      }                                                                                                             
1141                                                                                                                    
1142      /**                                                                                                           
1143       * Update the order of the workspace screens in the database. The array list contains                         
1144       * a list of screen ids in the order that they should appear.                                                 
1145       */                                                                                                           
1146      void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                             
1147          // Log to disk                                                                                            
1148          Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                                
1149          Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);                 
1150                                                                                                                    
1151          final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                         
1152          final ContentResolver cr = context.getContentResolver();                                                  
1153          final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                            
1154                                                                                                                    
1155          // Remove any negative screen ids -- these aren't persisted                                               
1156          Iterator<Long> iter = screensCopy.iterator();                                                             
1157          while (iter.hasNext()) {                                                                                  
1158              long id = iter.next();                                                                                
1159              if (id < 0) {                                                                                         
1160                  iter.remove();                                                                                    
1161              }                                                                                                     
1162          }                                                                                                         
1163                                                                                                                    
1164          Runnable r = new Runnable() {                                                                             
1165              @Override                                                                                             
1166              public void run() {                                                                                   
1167                  ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();              
1168                  // Clear the table                                                                                
1169                  ops.add(ContentProviderOperation.newDelete(uri).build());                                         
1170                  int count = screensCopy.size();                                                                   
1171                  for (int i = 0; i < count; i++) {                                                                 
1172                      ContentValues v = new ContentValues();                                                        
1173                      long screenId = screensCopy.get(i);                                                           
1174                      v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                                       
1175                      v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                                      
1176                      ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());                       
1177                  }                                                                                                 
1178                                                                                                                    
1179                  try {                                                                                             
1180                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
1181                  } catch (Exception ex) {                                                                          
1182                      throw new RuntimeException(ex);                                                               
1183                  }                                                                                                 
1184                                                                                                                    
1185                  synchronized (sBgLock) {                                                                          
1186                      sBgWorkspaceScreens.clear();                                                                  
1187                      sBgWorkspaceScreens.addAll(screensCopy);                                                      
1188                  }                                                                                                 
1189              }                                                                                                     
1190          };                                                                                                        
1191          runOnWorkerThread(r);                                                                                     
1192      }                                                                                                             
1193                                                                                                                    
1194      /**                                                                                                           
1195       * Remove the contents of the specified folder from the database                                              
1196       */                                                                                                           
1197      static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                        
1198          final ContentResolver cr = context.getContentResolver();                                                  
1199                                                                                                                    
1200          Runnable r = new Runnable() {                                                                             
1201              public void run() {                                                                                   
1202                  cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);                  
1203                  // Lock on mBgLock *after* the db operation                                                       
1204                  synchronized (sBgLock) {                                                                          
1205                      sBgItemsIdMap.remove(info.id);                                                                
1206                      sBgFolders.remove(info.id);                                                                   
1207 -                    sBgDbIconCache.remove(info);                                                                  
1208                      sBgWorkspaceItems.remove(info);                                                               
1209                  }                                                                                                 
1210                                                                                                                    
1211                  cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                 
1212                          LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                              
1213                  // Lock on mBgLock *after* the db operation                                                       
1214                  synchronized (sBgLock) {                                                                          
1215                      for (ItemInfo childInfo : info.contents) {                                                    
1216                          sBgItemsIdMap.remove(childInfo.id);                                                       
1217 -                        sBgDbIconCache.remove(childInfo);                                                         
1218                      }                                                                                             
1219                  }                                                                                                 
1220              }                                                                                                     
1221          };                                                                                                        
1222          runOnWorkerThread(r);                                                                                     
1223      }                                                                                                             
1224                                                                                                                    
1225      /**                                                                                                           
1226       * Set this as the current Launcher activity object for the loader.                                           
1227       */                                                                                                           
1228      public void initialize(Callbacks callbacks) {                                                                 
1229          synchronized (mLock) {                                                                                    
1230              mCallbacks = new WeakReference<Callbacks>(callbacks);                                                 
1231          }                                                                                                         
1232      }                                                                                                             
1233                                                                                                                    
1234      @Override                                                                                                     
1235      public void onPackageChanged(String packageName, UserHandleCompat user) {                                     
1236          int op = PackageUpdatedTask.OP_UPDATE;                                                                    
1237          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1238                  user));                                                                                           
1239      }                                                                                                             
1240                                                                                                                    
1241      @Override                                                                                                     
1242      public void onPackageRemoved(String packageName, UserHandleCompat user) {                                     
1243          int op = PackageUpdatedTask.OP_REMOVE;                                                                    
1244          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1245                  user));                                                                                           
1246      }                                                                                                             
1247                                                                                                                    
1248      @Override                                                                                                     
1249      public void onPackageAdded(String packageName, UserHandleCompat user) {                                       
1250          int op = PackageUpdatedTask.OP_ADD;                                                                       
1251          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1252                  user));                                                                                           
1253      }                                                                                                             
1254                                                                                                                    
1255      @Override                                                                                                     
1256      public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                                 
1257              boolean replacing) {                                                                                  
1258          if (!replacing) {                                                                                         
1259              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,                 
1260                      user));                                                                                       
1261              if (mAppsCanBeOnRemoveableStorage) {                                                                  
1262                  // Only rebind if we support removable storage. It catches the                                    
1263                  // case where                                                                                     
1264                  // apps on the external sd card need to be reloaded                                               
1265                  startLoaderFromBackground();                                                                      
1266              }                                                                                                     
1267          } else {                                                                                                  
1268              // If we are replacing then just update the packages in the list                                      
1269              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                            
1270                      packageNames, user));                                                                         
1271          }                                                                                                         
1272      }                                                                                                             
1273                                                                                                                    
1274      @Override                                                                                                     
1275      public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                               
1276              boolean replacing) {                                                                                  
1277          if (!replacing) {                                                                                         
1278              enqueuePackageUpdated(new PackageUpdatedTask(                                                         
1279                      PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                              
1280                      user));                                                                                       
1281          }                                                                                                         
1282      }                                                                                                             
1283                                                                                                                    
1284      /**                                                                                                           
1285       * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                                 
1286       * ACTION_PACKAGE_CHANGED.                                                                                    
1287       */                                                                                                           
1288      @Override                                                                                                     
1289      public void onReceive(Context context, Intent intent) {                                                       
1290          if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                             
1291                                                                                                                    
1292          final String action = intent.getAction();                                                                 
1293          if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                                        
1294              // If we have changed locale we need to clear out the labels in all apps/workspace.                   
1295              forceReload();                                                                                        
1296          } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                          
1297               // Check if configuration change was an mcc/mnc change which would affect app resources              
1298               // and we would need to clear out the labels in all apps/workspace. Same handling as                 
1299               // above for ACTION_LOCALE_CHANGED                                                                   
1300               Configuration currentConfig = context.getResources().getConfiguration();                             
1301               if (mPreviousConfigMcc != currentConfig.mcc) {                                                       
1302                     Log.d(TAG, "Reload apps on config change. curr_mcc:"                                           
1303                         + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                                   
1304                     forceReload();                                                                                 
1305               }                                                                                                    
1306               // Update previousConfig                                                                             
1307               mPreviousConfigMcc = currentConfig.mcc;                                                              
1308          } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                          
1309                     SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                              
1310              Callbacks callbacks = getCallback();                                                                  
1311              if (callbacks != null) {                                                                              
1312                  callbacks.bindSearchablesChanged();                                                               
1313              }                                                                                                     
1314          }                                                                                                         
1315      }                                                                                                             
1316                                                                                                                    
1317      void forceReload() {                                                                                          
1318          resetLoadedState(true, true);                                                                             
1319                                                                                                                    
1320          // Do this here because if the launcher activity is running it will be restarted.                         
1321          // If it's not running startLoaderFromBackground will merely tell it that it needs                        
1322          // to reload.                                                                                             
1323          startLoaderFromBackground();                                                                              
1324      }                                                                                                             
1325                                                                                                                    
1326      public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {                      
1327          synchronized (mLock) {                                                                                    
1328              // Stop any existing loaders first, so they don't set mAllAppsLoaded or                               
1329              // mWorkspaceLoaded to true later                                                                     
1330              stopLoaderLocked();                                                                                   
1331              if (resetAllAppsLoaded) mAllAppsLoaded = false;                                                       
1332              if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                                   
1333          }                                                                                                         
1334      }                                                                                                             
1335                                                                                                                    
1336      /**                                                                                                           
1337       * When the launcher is in the background, it's possible for it to miss paired                                
1338       * configuration changes.  So whenever we trigger the loader from the background                              
1339       * tell the launcher that it needs to re-run the loader when it comes back instead                            
1340       * of doing it now.                                                                                           
1341       */                                                                                                           
1342      public void startLoaderFromBackground() {                                                                     
1343          boolean runLoader = false;                                                                                
1344          Callbacks callbacks = getCallback();                                                                      
1345          if (callbacks != null) {                                                                                  
1346              // Only actually run the loader if they're not paused.                                                
1347              if (!callbacks.setLoadOnResume()) {                                                                   
1348                  runLoader = true;                                                                                 
1349              }                                                                                                     
1350          }                                                                                                         
1351          if (runLoader) {                                                                                          
1352              startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                                   
1353          }                                                                                                         
1354      }                                                                                                             
1355                                                                                                                    
1356      // If there is already a loader task running, tell it to stop.                                                
1357      // returns true if isLaunching() was true on the old task                                                     
1358      private boolean stopLoaderLocked() {                                                                          
1359          boolean isLaunching = false;                                                                              
1360          LoaderTask oldTask = mLoaderTask;                                                                         
1361          if (oldTask != null) {                                                                                    
1362              if (oldTask.isLaunching()) {                                                                          
1363                  isLaunching = true;                                                                               
1364              }                                                                                                     
1365              oldTask.stopLocked();                                                                                 
1366          }                                                                                                         
1367          return isLaunching;                                                                                       
1368      }                                                                                                             
1369                                                                                                                    
1370      public boolean isCurrentCallbacks(Callbacks callbacks) {                                                      
1371          return (mCallbacks != null && mCallbacks.get() == callbacks);                                             
1372      }                                                                                                             
1373                                                                                                                    
1374      public void startLoader(boolean isLaunching, int synchronousBindPage) {                                       
1375          startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                          
1376      }                                                                                                             
1377                                                                                                                    
1378      public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {                        
1379          synchronized (mLock) {                                                                                    
1380              if (DEBUG_LOADERS) {                                                                                  
1381                  Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                             
1382              }                                                                                                     
1383                                                                                                                    
1384              // Clear any deferred bind-runnables from the synchronized load process                               
1385              // We must do this before any loading/binding is scheduled below.                                     
1386              synchronized (mDeferredBindRunnables) {                                                               
1387                  mDeferredBindRunnables.clear();                                                                   
1388              }                                                                                                     
1389                                                                                                                    
1390              // Don't bother to start the thread if we know it's not going to do anything                          
1391              if (mCallbacks != null && mCallbacks.get() != null) {                                                 
1392                  // If there is already one running, tell it to stop.                                              
1393                  // also, don't downgrade isLaunching if we're already running                                     
1394                  isLaunching = isLaunching || stopLoaderLocked();                                                  
1395                  mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                          
1396                  if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                         
1397                          && mAllAppsLoaded && mWorkspaceLoaded) {                                                  
1398                      mLoaderTask.runBindSynchronousPage(synchronousBindPage);                                      
1399                  } else {                                                                                          
1400                      sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                              
1401                      sWorker.post(mLoaderTask);                                                                    
1402                  }                                                                                                 
1403              }                                                                                                     
1404          }                                                                                                         
1405      }                                                                                                             
1406                                                                                                                    
1407      void bindRemainingSynchronousPages() {                                                                        
1408          // Post the remaining side pages to be loaded                                                             
1409          if (!mDeferredBindRunnables.isEmpty()) {                                                                  
1410              Runnable[] deferredBindRunnables = null;                                                              
1411              synchronized (mDeferredBindRunnables) {                                                               
1412                  deferredBindRunnables = mDeferredBindRunnables.toArray(                                           
1413                          new Runnable[mDeferredBindRunnables.size()]);                                             
1414                  mDeferredBindRunnables.clear();                                                                   
1415              }                                                                                                     
1416              for (final Runnable r : deferredBindRunnables) {                                                      
1417                  mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                                   
1418              }                                                                                                     
1419          }                                                                                                         
1420      }                                                                                                             
1421                                                                                                                    
1422      public void stopLoader() {                                                                                    
1423          synchronized (mLock) {                                                                                    
1424              if (mLoaderTask != null) {                                                                            
1425                  mLoaderTask.stopLocked();                                                                         
1426              }                                                                                                     
1427          }                                                                                                         
1428      }                                                                                                             
1429                                                                                                                    
1430      /**                                                                                                           
1431       * Loads the workspace screen ids in an ordered list.                                                         
1432       */                                                                                                           
1433      private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                                      
1434          final ContentResolver contentResolver = context.getContentResolver();                                     
1435          final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                     
1436                                                                                                                    
1437          // Get screens ordered by rank.                                                                           
1438          final Cursor sc = contentResolver.query(screensUri, null, null, null,                                     
1439                  LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                                   
1440          ArrayList<Long> screenIds = new ArrayList<Long>();                                                        
1441          try {                                                                                                     
1442              final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);                  
1443              while (sc.moveToNext()) {                                                                             
1444                  try {                                                                                             
1445                      screenIds.add(sc.getLong(idIndex));                                                           
1446                  } catch (Exception e) {                                                                           
1447                      Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                                  
1448                              + " - invalid screens: " + e, true);                                                  
1449                  }                                                                                                 
1450              }                                                                                                     
1451          } finally {                                                                                               
1452              sc.close();                                                                                           
1453          }                                                                                                         
1454          return screenIds;                                                                                         
1455      }                                                                                                             
1456                                                                                                                    
1457      public boolean isAllAppsLoaded() {                                                                            
1458          return mAllAppsLoaded;                                                                                    
1459      }                                                                                                             
1460                                                                                                                    
1461      boolean isLoadingWorkspace() {                                                                                
1462          synchronized (mLock) {                                                                                    
1463              if (mLoaderTask != null) {                                                                            
1464                  return mLoaderTask.isLoadingWorkspace();                                                          
1465              }                                                                                                     
1466          }                                                                                                         
1467          return false;                                                                                             
1468      }                                                                                                             
1469                                                                                                                    
1470      /**                                                                                                           
1471       * Runnable for the thread that loads the contents of the launcher:                                           
1472       *   - workspace icons                                                                                        
1473       *   - widgets                                                                                                
1474       *   - all apps icons                                                                                         
1475       */                                                                                                           
1476      private class LoaderTask implements Runnable {                                                                
1477          private Context mContext;                                                                                 
1478          private boolean mIsLaunching;                                                                             
1479          private boolean mIsLoadingAndBindingWorkspace;                                                            
1480          private boolean mStopped;                                                                                 
1481          private boolean mLoadAndBindStepFinished;                                                                 
1482          private int mFlags;                                                                                       
1483                                                                                                                    
1484 -        private HashMap<Object, CharSequence> mLabelCache;                                                        
1485 -                                                                                                                  
1486          LoaderTask(Context context, boolean isLaunching, int flags) {                                             
1487              mContext = context;                                                                                   
1488              mIsLaunching = isLaunching;                                                                           
1489 -            mLabelCache = new HashMap<Object, CharSequence>();                                                    
1490              mFlags = flags;                                                                                       
1491          }                                                                                                         
1492                                                                                                                    
1493          boolean isLaunching() {                                                                                   
1494              return mIsLaunching;                                                                                  
1495          }                                                                                                         
1496                                                                                                                    
1497          boolean isLoadingWorkspace() {                                                                            
1498              return mIsLoadingAndBindingWorkspace;                                                                 
1499          }                                                                                                         
1500                                                                                                                    
1501          private void loadAndBindWorkspace() {                                                                     
1502              mIsLoadingAndBindingWorkspace = true;                                                                 
1503                                                                                                                    
1504              // Load the workspace                                                                                 
1505              if (DEBUG_LOADERS) {                                                                                  
1506                  Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                          
1507              }                                                                                                     
1508                                                                                                                    
1509              if (!mWorkspaceLoaded) {                                                                              
1510                  loadWorkspace();                                                                                  
1511                  synchronized (LoaderTask.this) {                                                                  
1512                      if (mStopped) {                                                                               
1513                          return;                                                                                   
1514                      }                                                                                             
1515                      mWorkspaceLoaded = true;                                                                      
1516                  }                                                                                                 
1517              }                                                                                                     
1518                                                                                                                    
1519              // Bind the workspace                                                                                 
1520              bindWorkspace(-1);                                                                                    
1521          }                                                                                                         
1522                                                                                                                    
1523          private void waitForIdle() {                                                                              
1524              // Wait until the either we're stopped or the other threads are done.                                 
1525              // This way we don't start loading all apps until the workspace has settled                           
1526              // down.                                                                                              
1527              synchronized (LoaderTask.this) {                                                                      
1528                  final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    
1529                                                                                                                    
1530                  mHandler.postIdle(new Runnable() {                                                                
1531                          public void run() {                                                                       
1532                              synchronized (LoaderTask.this) {                                                      
1533                                  mLoadAndBindStepFinished = true;                                                  
1534                                  if (DEBUG_LOADERS) {                                                              
1535                                      Log.d(TAG, "done with previous binding step");                                
1536                                  }                                                                                 
1537                                  LoaderTask.this.notify();                                                         
1538                              }                                                                                     
1539                          }                                                                                         
1540                      });                                                                                           
1541                                                                                                                    
1542                  while (!mStopped && !mLoadAndBindStepFinished) {                                                  
1543                      try {                                                                                         
1544                          // Just in case mFlushingWorkerThread changes but we aren't woken up,                     
1545                          // wait no longer than 1sec at a time                                                     
1546                          this.wait(1000);                                                                          
1547                      } catch (InterruptedException ex) {                                                           
1548                          // Ignore                                                                                 
1549                      }                                                                                             
1550                  }                                                                                                 
1551                  if (DEBUG_LOADERS) {                                                                              
1552                      Log.d(TAG, "waited "                                                                          
1553                              + (SystemClock.uptimeMillis()-workspaceWaitTime)                                      
1554                              + "ms for previous step to finish binding");                                          
1555                  }                                                                                                 
1556              }                                                                                                     
1557          }                                                                                                         
1558                                                                                                                    
1559          void runBindSynchronousPage(int synchronousBindPage) {                                                    
1560              if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                          
1561                  // Ensure that we have a valid page index to load synchronously                                   
1562                  throw new RuntimeException("Should not call runBindSynchronousPage() without " +                  
1563                          "valid page index");                                                                      
1564              }                                                                                                     
1565              if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                           
1566                  // Ensure that we don't try and bind a specified page when the pages have not been                
1567                  // loaded already (we should load everything asynchronously in that case)                         
1568                  throw new RuntimeException("Expecting AllApps and Workspace to be loaded");                       
1569              }                                                                                                     
1570              synchronized (mLock) {                                                                                
1571                  if (mIsLoaderTaskRunning) {                                                                       
1572                      // Ensure that we are never running the background loading at this point since                
1573                      // we also touch the background collections                                                   
1574                      throw new RuntimeException("Error! Background loading is already running");                   
1575                  }                                                                                                 
1576              }                                                                                                     
1577                                                                                                                    
1578              // XXX: Throw an exception if we are already loading (since we touch the worker thread                
1579              //      data structures, we can't allow any other thread to touch that data, but because              
1580              //      this call is synchronous, we can get away with not locking).                                  
1581                                                                                                                    
1582              // The LauncherModel is static in the LauncherAppState and mHandler may have queued                   
1583              // operations from the previous activity.  We need to ensure that all queued operations               
1584              // are executed before any synchronous binding work is done.                                          
1585              mHandler.flush();                                                                                     
1586                                                                                                                    
1587              // Divide the set of loaded items into those that we are binding synchronously, and                   
1588              // everything else that is to be bound normally (asynchronously).                                     
1589              bindWorkspace(synchronousBindPage);                                                                   
1590              // XXX: For now, continue posting the binding of AllApps as there are other issues that               
1591              //      arise from that.                                                                              
1592              onlyBindAllApps();                                                                                    
1593          }                                                                                                         
1594                                                                                                                    
1595          public void run() {                                                                                       
1596              synchronized (mLock) {                                                                                
1597                  mIsLoaderTaskRunning = true;                                                                      
1598              }                                                                                                     
1599              // Optimize for end-user experience: if the Launcher is up and // running with the                    
1600              // All Apps interface in the foreground, load All Apps first. Otherwise, load the                     
1601              // workspace first (default).                                                                         
1602              keep_running: {                                                                                       
1603                  // Elevate priority when Home launches for the first time to avoid                                
1604                  // starving at boot time. Staring at a blank home is not cool.                                    
1605                  synchronized (mLock) {                                                                            
1606                      if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                                 
1607                              (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                           
1608                      android.os.Process.setThreadPriority(mIsLaunching                                             
1609                              ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);              
1610                  }                                                                                                 
1611                  if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                                       
1612                  loadAndBindWorkspace();                                                                           
1613                                                                                                                    
1614                  if (mStopped) {                                                                                   
1615                      break keep_running;                                                                           
1616                  }                                                                                                 
1617                                                                                                                    
1618                  // Whew! Hard work done.  Slow us down, and wait until the UI thread has                          
1619                  // settled down.                                                                                  
1620                  synchronized (mLock) {                                                                            
1621                      if (mIsLaunching) {                                                                           
1622                          if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                   
1623                          android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                 
1624                      }                                                                                             
1625                  }                                                                                                 
1626                  waitForIdle();                                                                                    
1627                                                                                                                    
1628                  // second step                                                                                    
1629                  if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                                        
1630                  loadAndBindAllApps();                                                                             
1631                                                                                                                    
1632                  // Restore the default thread priority after we are done loading items                            
1633                  synchronized (mLock) {                                                                            
1634                      android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                        
1635                  }                                                                                                 
1636              }                                                                                                     
1637                                                                                                                    
1638 -            // Update the saved icons if necessary                                                                
1639 -            if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                            
1640 -            synchronized (sBgLock) {                                                                              
1641 -                for (Object key : sBgDbIconCache.keySet()) {                                                      
1642 -                    updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));                       
1643 -                }                                                                                                 
1644 -                sBgDbIconCache.clear();                                                                           
1645 -            }                                                                                                     
1646 -                                                                                                                  
1647              if (LauncherAppState.isDisableAllApps()) {                                                            
1648                  // Ensure that all the applications that are in the system are                                    
1649                  // represented on the home screen.                                                                
1650                  verifyApplications();                                                                             
1651              }                                                                                                     
1652                                                                                                                    
1653              // Clear out this reference, otherwise we end up holding it until all of the                          
1654              // callback runnables are done.                                                                       
1655              mContext = null;                                                                                      
1656                                                                                                                    
1657              synchronized (mLock) {                                                                                
1658                  // If we are still the last one to be scheduled, remove ourselves.                                
1659                  if (mLoaderTask == this) {                                                                        
1660                      mLoaderTask = null;                                                                           
1661                  }                                                                                                 
1662                  mIsLoaderTaskRunning = false;                                                                     
1663              }                                                                                                     
1664          }                                                                                                         
1665                                                                                                                    
1666          public void stopLocked() {                                                                                
1667              synchronized (LoaderTask.this) {                                                                      
1668                  mStopped = true;                                                                                  
1669                  this.notify();                                                                                    
1670              }                                                                                                     
1671          }                                                                                                         
1672                                                                                                                    
1673          /**                                                                                                       
1674           * Gets the callbacks object.  If we've been stopped, or if the launcher object                           
1675           * has somehow been garbage collected, return null instead.  Pass in the Callbacks                        
1676           * object that was around when the deferred message was scheduled, and if there's                         
1677           * a new Callbacks object around then also return null.  This will save us from                           
1678           * calling onto it with data that will be ignored.                                                        
1679           */                                                                                                       
1680          Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                                       
1681              synchronized (mLock) {                                                                                
1682                  if (mStopped) {                                                                                   
1683                      return null;                                                                                  
1684                  }                                                                                                 
1685                                                                                                                    
1686                  if (mCallbacks == null) {                                                                         
1687                      return null;                                                                                  
1688                  }                                                                                                 
1689                                                                                                                    
1690                  final Callbacks callbacks = mCallbacks.get();                                                     
1691                  if (callbacks != oldCallbacks) {                                                                  
1692                      return null;                                                                                  
1693                  }                                                                                                 
1694                  if (callbacks == null) {                                                                          
1695                      Log.w(TAG, "no mCallbacks");                                                                  
1696                      return null;                                                                                  
1697                  }                                                                                                 
1698                                                                                                                    
1699                  return callbacks;                                                                                 
1700              }                                                                                                     
1701          }                                                                                                         
1702                                                                                                                    
1703          private void verifyApplications() {                                                                       
1704              final Context context = mApp.getContext();                                                            
1705                                                                                                                    
1706              // Cross reference all the applications in our apps list with items in the workspace                  
1707              ArrayList<ItemInfo> tmpInfos;                                                                         
1708              ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                                
1709              synchronized (sBgLock) {                                                                              
1710                  for (AppInfo app : mBgAllAppsList.data) {                                                         
1711                      tmpInfos = getItemInfoForComponentName(app.componentName, app.user);                          
1712                      if (tmpInfos.isEmpty()) {                                                                     
1713                          // We are missing an application icon, so add this to the workspace                       
1714                          added.add(app);                                                                           
1715                          // This is a rare event, so lets log it                                                   
1716                          Log.e(TAG, "Missing Application on load: " + app);                                        
1717                      }                                                                                             
1718                  }                                                                                                 
1719              }                                                                                                     
1720              if (!added.isEmpty()) {                                                                               
1721                  addAndBindAddedWorkspaceApps(context, added);                                                     
1722              }                                                                                                     
1723          }                                                                                                         
1724                                                                                                                    
1725          // check & update map of what's occupied; used to discard overlapping/invalid items                       
1726          private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {                 
1727              LauncherAppState app = LauncherAppState.getInstance();                                                
1728              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1729              final int countX = (int) grid.numColumns;                                                             
1730              final int countY = (int) grid.numRows;                                                                
1731                                                                                                                    
1732              long containerIndex = item.screenId;                                                                  
1733              if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1734                  // Return early if we detect that an item is under the hotseat button                             
1735                  if (mCallbacks == null ||                                                                         
1736                          mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                              
1737                      Log.e(TAG, "Error loading shortcut into hotseat " + item                                      
1738                              + " into position (" + item.screenId + ":" + item.cellX + ","                         
1739                              + item.cellY + ") occupied by all apps");                                             
1740                      return false;                                                                                 
1741                  }                                                                                                 
1742                                                                                                                    
1743                  final ItemInfo[][] hotseatItems =                                                                 
1744                          occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);                        
1745                                                                                                                    
1746                  if (item.screenId >= grid.numHotseatIcons) {                                                      
1747                      Log.e(TAG, "Error loading shortcut " + item                                                   
1748                              + " into hotseat position " + item.screenId                                           
1749                              + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)                     
1750                              + ")");                                                                               
1751                      return false;                                                                                 
1752                  }                                                                                                 
1753                                                                                                                    
1754                  if (hotseatItems != null) {                                                                       
1755                      if (hotseatItems[(int) item.screenId][0] != null) {                                           
1756                          Log.e(TAG, "Error loading shortcut into hotseat " + item                                  
1757                                  + " into position (" + item.screenId + ":" + item.cellX + ","                     
1758                                  + item.cellY + ") occupied by "                                                   
1759                                  + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)                      
1760                                  [(int) item.screenId][0]);                                                        
1761                              return false;                                                                         
1762                      } else {                                                                                      
1763                          hotseatItems[(int) item.screenId][0] = item;                                              
1764                          return true;                                                                              
1765                      }                                                                                             
1766                  } else {                                                                                          
1767                      final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];                       
1768                      items[(int) item.screenId][0] = item;                                                         
1769                      occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);                     
1770                      return true;                                                                                  
1771                  }                                                                                                 
1772              } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                          
1773                  // Skip further checking if it is not the hotseat or workspace container                          
1774                  return true;                                                                                      
1775              }                                                                                                     
1776                                                                                                                    
1777              if (!occupied.containsKey(item.screenId)) {                                                           
1778                  ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                                        
1779                  occupied.put(item.screenId, items);                                                               
1780              }                                                                                                     
1781                                                                                                                    
1782              final ItemInfo[][] screens = occupied.get(item.screenId);                                             
1783              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
1784                      item.cellX < 0 || item.cellY < 0 ||                                                           
1785                      item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {                       
1786                  Log.e(TAG, "Error loading shortcut " + item                                                       
1787                          + " into cell (" + containerIndex + "-" + item.screenId + ":"                             
1788                          + item.cellX + "," + item.cellY                                                           
1789                          + ") out of screen bounds ( " + countX + "x" + countY + ")");                             
1790                  return false;                                                                                     
1791              }                                                                                                     
1792                                                                                                                    
1793              // Check if any workspace icons overlap with each other                                               
1794              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1795                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1796                      if (screens[x][y] != null) {                                                                  
1797                          Log.e(TAG, "Error loading shortcut " + item                                               
1798                              + " into cell (" + containerIndex + "-" + item.screenId + ":"                         
1799                              + x + "," + y                                                                         
1800                              + ") occupied by "                                                                    
1801                              + screens[x][y]);                                                                     
1802                          return false;                                                                             
1803                      }                                                                                             
1804                  }                                                                                                 
1805              }                                                                                                     
1806              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1807                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1808                      screens[x][y] = item;                                                                         
1809                  }                                                                                                 
1810              }                                                                                                     
1811                                                                                                                    
1812              return true;                                                                                          
1813          }                                                                                                         
1814                                                                                                                    
1815          /** Clears all the sBg data structures */                                                                 
1816          private void clearSBgDataStructures() {                                                                   
1817              synchronized (sBgLock) {                                                                              
1818                  sBgWorkspaceItems.clear();                                                                        
1819                  sBgAppWidgets.clear();                                                                            
1820                  sBgFolders.clear();                                                                               
1821                  sBgItemsIdMap.clear();                                                                            
1822 -                sBgDbIconCache.clear();                                                                           
1823                  sBgWorkspaceScreens.clear();                                                                      
1824              }                                                                                                     
1825          }                                                                                                         
1826                                                                                                                    
1827          private void loadWorkspace() {                                                                            
1828              // Log to disk                                                                                        
1829              Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                         
1830                                                                                                                    
1831              final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                        
1832                                                                                                                    
1833              final Context context = mContext;                                                                     
1834              final ContentResolver contentResolver = context.getContentResolver();                                 
1835              final PackageManager manager = context.getPackageManager();                                           
1836              final boolean isSafeMode = manager.isSafeMode();                                                      
1837              final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                      
1838              final boolean isSdCardReady = context.registerReceiver(null,                                          
1839                      new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                                      
1840                                                                                                                    
1841              LauncherAppState app = LauncherAppState.getInstance();                                                
1842              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1843              int countX = (int) grid.numColumns;                                                                   
1844              int countY = (int) grid.numRows;                                                                      
1845                                                                                                                    
1846              if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                                    
1847                  Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);                     
1848                  LauncherAppState.getLauncherProvider().deleteDatabase();                                          
1849              }                                                                                                     
1850                                                                                                                    
1851              if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                                  
1852                  // append the user's Launcher2 shortcuts                                                          
1853                  Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);                        
1854                  LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                               
1855              } else {                                                                                              
1856                  // Make sure the default workspace is loaded                                                      
1857                  Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);                      
1858                  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                         
1859              }                                                                                                     
1860                                                                                                                    
1861              synchronized (sBgLock) {                                                                              
1862                  clearSBgDataStructures();                                                                         
1863                  final HashSet<String> installingPkgs = PackageInstallerCompat                                     
1864                          .getInstance(mContext).updateAndGetActiveSessionCache();                                  
1865                                                                                                                    
1866                  final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                                      
1867                  final ArrayList<Long> restoredRows = new ArrayList<Long>();                                       
1868                  final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;                    
1869                  if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                                
1870                  final Cursor c = contentResolver.query(contentUri, null, null, null, null);                       
1871                                                                                                                    
1872                  // +1 for the hotseat (it can be larger than the workspace)                                       
1873                  // Load workspace in reverse order to ensure that latest items are loaded first (and              
1874                  // before any earlier duplicates)                                                                 
1875                  final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();                   
1876                                                                                                                    
1877                  try {                                                                                             
1878                      final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);                  
1879                      final int intentIndex = c.getColumnIndexOrThrow                                               
1880                              (LauncherSettings.Favorites.INTENT);                                                  
1881                      final int titleIndex = c.getColumnIndexOrThrow                                                
1882                              (LauncherSettings.Favorites.TITLE);                                                   
1883                      final int iconTypeIndex = c.getColumnIndexOrThrow(                                            
1884                              LauncherSettings.Favorites.ICON_TYPE);                                                
1885                      final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);               
1886                      final int iconPackageIndex = c.getColumnIndexOrThrow(                                         
1887                              LauncherSettings.Favorites.ICON_PACKAGE);                                             
1888                      final int iconResourceIndex = c.getColumnIndexOrThrow(                                        
1889                              LauncherSettings.Favorites.ICON_RESOURCE);                                            
1890                      final int containerIndex = c.getColumnIndexOrThrow(                                           
1891                              LauncherSettings.Favorites.CONTAINER);                                                
1892                      final int itemTypeIndex = c.getColumnIndexOrThrow(                                            
1893                              LauncherSettings.Favorites.ITEM_TYPE);                                                
1894                      final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                         
1895                              LauncherSettings.Favorites.APPWIDGET_ID);                                             
1896                      final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                                   
1897                              LauncherSettings.Favorites.APPWIDGET_PROVIDER);                                       
1898                      final int screenIndex = c.getColumnIndexOrThrow(                                              
1899                              LauncherSettings.Favorites.SCREEN);                                                   
1900                      final int cellXIndex = c.getColumnIndexOrThrow                                                
1901                              (LauncherSettings.Favorites.CELLX);                                                   
1902                      final int cellYIndex = c.getColumnIndexOrThrow                                                
1903                              (LauncherSettings.Favorites.CELLY);                                                   
1904                      final int spanXIndex = c.getColumnIndexOrThrow                                                
1905                              (LauncherSettings.Favorites.SPANX);                                                   
1906                      final int spanYIndex = c.getColumnIndexOrThrow(                                               
1907                              LauncherSettings.Favorites.SPANY);                                                    
1908                      final int rankIndex = c.getColumnIndexOrThrow(                                                
1909                              LauncherSettings.Favorites.RANK);                                                     
1910                      final int restoredIndex = c.getColumnIndexOrThrow(                                            
1911                              LauncherSettings.Favorites.RESTORED);                                                 
1912                      final int profileIdIndex = c.getColumnIndexOrThrow(                                           
1913                              LauncherSettings.Favorites.PROFILE_ID);                                               
1914                      //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);               
1915                      //final int displayModeIndex = c.getColumnIndexOrThrow(                                       
1916                      //        LauncherSettings.Favorites.DISPLAY_MODE);                                           
1917                                                                                                                    
1918                      ShortcutInfo info;                                                                            
1919                      String intentDescription;                                                                     
1920                      LauncherAppWidgetInfo appWidgetInfo;                                                          
1921                      int container;                                                                                
1922                      long id;                                                                                      
1923                      Intent intent;                                                                                
1924                      UserHandleCompat user;                                                                        
1925                                                                                                                    
1926                      while (!mStopped && c.moveToNext()) {                                                         
1927                          try {                                                                                     
1928                              int itemType = c.getInt(itemTypeIndex);                                               
1929                              boolean restored = 0 != c.getInt(restoredIndex);                                      
1930                              boolean allowMissingTarget = false;                                                   
1931                                                                                                                    
1932                              switch (itemType) {                                                                   
1933                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1934                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1935                                  id = c.getLong(idIndex);                                                          
1936                                  intentDescription = c.getString(intentIndex);                                     
1937                                  long serialNumber = c.getInt(profileIdIndex);                                     
1938                                  user = mUserManager.getUserForSerialNumber(serialNumber);                         
1939                                  int promiseType = c.getInt(restoredIndex);                                        
1940                                  int disabledState = 0;                                                            
1941                                  boolean itemReplaced = false;                                                     
1942                                  if (user == null) {                                                               
1943                                      // User has been deleted remove the item.                                     
1944                                      itemsToRemove.add(id);                                                        
1945                                      continue;                                                                     
1946                                  }                                                                                 
1947                                  try {                                                                             
1948                                      intent = Intent.parseUri(intentDescription, 0);                               
1949                                      ComponentName cn = intent.getComponent();                                     
1950                                      if (cn != null && cn.getPackageName() != null) {                              
1951                                          boolean validPkg = launcherApps.isPackageEnabledForProfile(               
1952                                                  cn.getPackageName(), user);                                       
1953                                          boolean validComponent = validPkg &&                                      
1954                                                  launcherApps.isActivityEnabledForProfile(cn, user);               
1955                                                                                                                    
1956                                          if (validComponent) {                                                     
1957                                              if (restored) {                                                       
1958                                                  // no special handling necessary for this item                    
1959                                                  restoredRows.add(id);                                             
1960                                                  restored = false;                                                 
1961                                              }                                                                     
1962                                          } else if (validPkg) {                                                    
1963                                              intent = null;                                                        
1964                                              if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {         
1965                                                  // We allow auto install apps to have their intent                
1966                                                  // updated after an install.                                      
1967                                                  intent = manager.getLaunchIntentForPackage(                       
1968                                                          cn.getPackageName());                                     
1969                                                  if (intent != null) {                                             
1970                                                      ContentValues values = new ContentValues();                   
1971                                                      values.put(LauncherSettings.Favorites.INTENT,                 
1972                                                              intent.toUri(0));                                     
1973                                                      updateItem(id, values);                                       
1974                                                  }                                                                 
1975                                              }                                                                     
1976                                                                                                                    
1977                                              if (intent == null) {                                                 
1978                                                  // The app is installed but the component is no                   
1979                                                  // longer available.                                              
1980                                                  Launcher.addDumpLog(TAG,                                          
1981                                                          "Invalid component removed: " + cn, true);                
1982                                                  itemsToRemove.add(id);                                            
1983                                                  continue;                                                         
1984                                              } else {                                                              
1985                                                  // no special handling necessary for this item                    
1986                                                  restoredRows.add(id);                                             
1987                                                  restored = false;                                                 
1988                                              }                                                                     
1989                                          } else if (restored) {                                                    
1990                                              // Package is not yet available but might be                          
1991                                              // installed later.                                                   
1992                                              Launcher.addDumpLog(TAG,                                              
1993                                                      "package not yet restored: " + cn, true);                     
1994                                                                                                                    
1995                                              if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {         
1996                                                  // Restore has started once.                                      
1997                                              } else if (installingPkgs.contains(cn.getPackageName())) {            
1998                                                  // App restore has started. Update the flag                       
1999                                                  promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;                 
2000                                                  ContentValues values = new ContentValues();                       
2001                                                  values.put(LauncherSettings.Favorites.RESTORED,                   
2002                                                          promiseType);                                             
2003                                                  updateItem(id, values);                                           
2004                                              } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
2005                                                  // This is a common app. Try to replace this.                     
2006                                                  int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseTy🔵
2007                                                  CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, 🔵
2008                                                  if (parser.findDefaultApp()) {                                    
2009                                                      // Default app found. Replace it.                             
2010                                                      intent = parser.parsedIntent;                                 
2011                                                      cn = intent.getComponent();                                   
2012                                                      ContentValues values = parser.parsedValues;                   
2013                                                      values.put(LauncherSettings.Favorites.RESTORED, 0);           
2014                                                      updateItem(id, values);                                       
2015                                                      restored = false;                                             
2016                                                      itemReplaced = true;                                          
2017                                                                                                                    
2018                                                  } else if (REMOVE_UNRESTORED_ICONS) {                             
2019                                                      Launcher.addDumpLog(TAG,                                      
2020                                                              "Unrestored package removed: " + cn, true);           
2021                                                      itemsToRemove.add(id);                                        
2022                                                      continue;                                                     
2023                                                  }                                                                 
2024                                              } else if (REMOVE_UNRESTORED_ICONS) {                                 
2025                                                  Launcher.addDumpLog(TAG,                                          
2026                                                          "Unrestored package removed: " + cn, true);               
2027                                                  itemsToRemove.add(id);                                            
2028                                                  continue;                                                         
2029                                              }                                                                     
2030                                          } else if (launcherApps.isAppEnabled(                                     
2031                                                  manager, cn.getPackageName(),                                     
2032                                                  PackageManager.GET_UNINSTALLED_PACKAGES)) {                       
2033                                              // Package is present but not available.                              
2034                                              allowMissingTarget = true;                                            
2035                                              disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;             
2036                                          } else if (!isSdCardReady) {                                              
2037                                              // SdCard is not ready yet. Package might get available,              
2038                                              // once it is ready.                                                  
2039                                              Launcher.addDumpLog(TAG, "Invalid package: " + cn                     
2040                                                      + " (check again later)", true);                              
2041                                              HashSet<String> pkgs = sPendingPackages.get(user);                    
2042                                              if (pkgs == null) {                                                   
2043                                                  pkgs = new HashSet<String>();                                     
2044                                                  sPendingPackages.put(user, pkgs);                                 
2045                                              }                                                                     
2046                                              pkgs.add(cn.getPackageName());                                        
2047                                              allowMissingTarget = true;                                            
2048                                              // Add the icon on the workspace anyway.                              
2049                                                                                                                    
2050                                          } else {                                                                  
2051                                              // Do not wait for external media load anymore.                       
2052                                              // Log the invalid package, and remove it                             
2053                                              Launcher.addDumpLog(TAG,                                              
2054                                                      "Invalid package removed: " + cn, true);                      
2055                                              itemsToRemove.add(id);                                                
2056                                              continue;                                                             
2057                                          }                                                                         
2058                                      } else if (cn == null) {                                                      
2059                                          // For shortcuts with no component, keep them as they are                 
2060                                          restoredRows.add(id);                                                     
2061                                          restored = false;                                                         
2062                                      }                                                                             
2063                                  } catch (URISyntaxException e) {                                                  
2064                                      Launcher.addDumpLog(TAG,                                                      
2065                                              "Invalid uri: " + intentDescription, true);                           
2066                                      continue;                                                                     
2067                                  }                                                                                 
2068                                                                                                                    
2069                                  if (itemReplaced) {                                                               
2070                                      if (user.equals(UserHandleCompat.myUserHandle())) {                           
2071 -                                        info = getShortcutInfo(manager, intent, user, context, null,              
2072 -                                                iconIndex, titleIndex, mLabelCache, false);                       
2073 +                                        info = getAppShortcutInfo(manager, intent, user, context, null,           
2074 +                                                iconIndex, titleIndex, false);                                    
2075                                      } else {                                                                      
2076                                          // Don't replace items for other profiles.                                
2077                                          itemsToRemove.add(id);                                                    
2078                                          continue;                                                                 
2079                                      }                                                                             
2080                                  } else if (restored) {                                                            
2081                                      if (user.equals(UserHandleCompat.myUserHandle())) {                           
2082                                          Launcher.addDumpLog(TAG,                                                  
2083                                                  "constructing info for partially restored package",               
2084                                                  true);                                                            
2085                                          info = getRestoredItemInfo(c, titleIndex, intent, promiseType);           
2086                                          intent = getRestoredItemIntent(c, context, intent);                       
2087                                      } else {                                                                      
2088                                          // Don't restore items for other profiles.                                
2089                                          itemsToRemove.add(id);                                                    
2090                                          continue;                                                                 
2091                                      }                                                                             
2092                                  } else if (itemType ==                                                            
2093                                          LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                       
2094 -                                    info = getShortcutInfo(manager, intent, user, context, c,                     
2095 -                                            iconIndex, titleIndex, mLabelCache, allowMissingTarget);              
2096 +                                    info = getAppShortcutInfo(manager, intent, user, context, c,                  
2097 +                                            iconIndex, titleIndex, allowMissingTarget);                           
2098                                  } else {                                                                          
2099                                      info = getShortcutInfo(c, context, iconTypeIndex,                             
2100                                              iconPackageIndex, iconResourceIndex, iconIndex,                       
2101                                              titleIndex);                                                          
2102                                                                                                                    
2103                                      // App shortcuts that used to be automatically added to Launcher              
2104                                      // didn't always have the correct intent flags set, so do that                
2105                                      // here                                                                       
2106                                      if (intent.getAction() != null &&                                             
2107                                          intent.getCategories() != null &&                                         
2108                                          intent.getAction().equals(Intent.ACTION_MAIN) &&                          
2109                                          intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {              
2110                                          intent.addFlags(                                                          
2111                                              Intent.FLAG_ACTIVITY_NEW_TASK |                                       
2112                                              Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                           
2113                                      }                                                                             
2114                                  }                                                                                 
2115                                                                                                                    
2116                                  if (info != null) {                                                               
2117                                      info.id = id;                                                                 
2118                                      info.intent = intent;                                                         
2119                                      container = c.getInt(containerIndex);                                         
2120                                      info.container = container;                                                   
2121                                      info.screenId = c.getInt(screenIndex);                                        
2122                                      info.cellX = c.getInt(cellXIndex);                                            
2123                                      info.cellY = c.getInt(cellYIndex);                                            
2124                                      info.rank = c.getInt(rankIndex);                                              
2125                                      info.spanX = 1;                                                               
2126                                      info.spanY = 1;                                                               
2127                                      info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);                   
2128                                      info.isDisabled = disabledState;                                              
2129                                      if (isSafeMode && !Utilities.isSystemApp(context, intent)) {                  
2130                                          info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;                   
2131                                      }                                                                             
2132                                                                                                                    
2133                                      // check & update map of what's occupied                                      
2134                                      if (!checkItemPlacement(occupied, info)) {                                    
2135                                          itemsToRemove.add(id);                                                    
2136                                          break;                                                                    
2137                                      }                                                                             
2138                                                                                                                    
2139                                      switch (container) {                                                          
2140                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2141                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2142                                          sBgWorkspaceItems.add(info);                                              
2143                                          break;                                                                    
2144                                      default:                                                                      
2145                                          // Item is in a user folder                                               
2146                                          FolderInfo folderInfo =                                                   
2147                                                  findOrMakeFolder(sBgFolders, container);                          
2148                                          folderInfo.add(info);                                                     
2149                                          break;                                                                    
2150                                      }                                                                             
2151                                      sBgItemsIdMap.put(info.id, info);                                             
2152 -                                                                                                                  
2153 -                                    // now that we've loaded everthing re-save it with the                        
2154 -                                    // icon in case it disappears somehow.                                        
2155 -                                    queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);                     
2156                                  } else {                                                                          
2157                                      throw new RuntimeException("Unexpected null ShortcutInfo");                   
2158                                  }                                                                                 
2159                                  break;                                                                            
2160                                                                                                                    
2161                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
2162                                  id = c.getLong(idIndex);                                                          
2163                                  FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                         
2164                                                                                                                    
2165                                  folderInfo.title = c.getString(titleIndex);                                       
2166                                  folderInfo.id = id;                                                               
2167                                  container = c.getInt(containerIndex);                                             
2168                                  folderInfo.container = container;                                                 
2169                                  folderInfo.screenId = c.getInt(screenIndex);                                      
2170                                  folderInfo.cellX = c.getInt(cellXIndex);                                          
2171                                  folderInfo.cellY = c.getInt(cellYIndex);                                          
2172                                  folderInfo.spanX = 1;                                                             
2173                                  folderInfo.spanY = 1;                                                             
2174                                                                                                                    
2175                                  // check & update map of what's occupied                                          
2176                                  if (!checkItemPlacement(occupied, folderInfo)) {                                  
2177                                      itemsToRemove.add(id);                                                        
2178                                      break;                                                                        
2179                                  }                                                                                 
2180                                                                                                                    
2181                                  switch (container) {                                                              
2182                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2183                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2184                                          sBgWorkspaceItems.add(folderInfo);                                        
2185                                          break;                                                                    
2186                                  }                                                                                 
2187                                                                                                                    
2188                                  if (restored) {                                                                   
2189                                      // no special handling required for restored folders                          
2190                                      restoredRows.add(id);                                                         
2191                                  }                                                                                 
2192                                                                                                                    
2193                                  sBgItemsIdMap.put(folderInfo.id, folderInfo);                                     
2194                                  sBgFolders.put(folderInfo.id, folderInfo);                                        
2195                                  break;                                                                            
2196                                                                                                                    
2197                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
2198                              case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                           
2199                                  // Read all Launcher-specific widget details                                      
2200                                  boolean customWidget = itemType ==                                                
2201                                      LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;                        
2202                                                                                                                    
2203                                  int appWidgetId = c.getInt(appWidgetIdIndex);                                     
2204                                  String savedProvider = c.getString(appWidgetProviderIndex);                       
2205                                  id = c.getLong(idIndex);                                                          
2206                                  final ComponentName component =                                                   
2207                                          ComponentName.unflattenFromString(savedProvider);                         
2208                                                                                                                    
2209                                  final int restoreStatus = c.getInt(restoredIndex);                                
2210                                  final boolean isIdValid = (restoreStatus &                                        
2211                                          LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                            
2212                                                                                                                    
2213                                  final boolean wasProviderReady = (restoreStatus &                                 
2214                                          LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;                      
2215                                                                                                                    
2216                                  final LauncherAppWidgetProviderInfo provider =                                    
2217                                          LauncherModel.getProviderInfo(context,                                    
2218                                                  ComponentName.unflattenFromString(savedProvider));                
2219                                                                                                                    
2220                                  final boolean isProviderReady = isValidProvider(provider);                        
2221                                  if (!isSafeMode && !customWidget &&                                               
2222                                          wasProviderReady && !isProviderReady) {                                   
2223                                      String log = "Deleting widget that isn't installed anymore: "                 
2224                                              + "id=" + id + " appWidgetId=" + appWidgetId;                         
2225                                                                                                                    
2226                                      Log.e(TAG, log);                                                              
2227                                      Launcher.addDumpLog(TAG, log, false);                                         
2228                                      itemsToRemove.add(id);                                                        
2229                                  } else {                                                                          
2230                                      if (isProviderReady) {                                                        
2231                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2232                                                  provider.provider);                                               
2233                                                                                                                    
2234                                          if (!customWidget) {                                                      
2235                                              int[] minSpan =                                                       
2236                                                      Launcher.getMinSpanForWidget(context, provider);              
2237                                              appWidgetInfo.minSpanX = minSpan[0];                                  
2238                                              appWidgetInfo.minSpanY = minSpan[1];                                  
2239                                          }                                                                         
2240                                                                                                                    
2241                                          int status = restoreStatus;                                               
2242                                          if (!wasProviderReady) {                                                  
2243                                              // If provider was not previously ready, update the                   
2244                                              // status and UI flag.                                                
2245                                                                                                                    
2246                                              // Id would be valid only if the widget restore broadcast was received🔵
2247                                              if (isIdValid) {                                                      
2248                                                  status = LauncherAppWidgetInfo.RESTORE_COMPLETED;                 
2249                                              } else {                                                              
2250                                                  status &= ~LauncherAppWidgetInfo                                  
2251                                                          .FLAG_PROVIDER_NOT_READY;                                 
2252                                              }                                                                     
2253                                          }                                                                         
2254                                          appWidgetInfo.restoreStatus = status;                                     
2255                                      } else {                                                                      
2256                                          Log.v(TAG, "Widget restore pending id=" + id                              
2257                                                  + " appWidgetId=" + appWidgetId                                   
2258                                                  + " status =" + restoreStatus);                                   
2259                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2260                                                  component);                                                       
2261                                          appWidgetInfo.restoreStatus = restoreStatus;                              
2262                                                                                                                    
2263                                          if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {  
2264                                              // Restore has started once.                                          
2265                                          } else if (installingPkgs.contains(component.getPackageName())) {         
2266                                              // App restore has started. Update the flag                           
2267                                              appWidgetInfo.restoreStatus |=                                        
2268                                                      LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;                   
2269                                          } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {                      
2270                                              Launcher.addDumpLog(TAG,                                              
2271                                                      "Unrestored widget removed: " + component, true);             
2272                                              itemsToRemove.add(id);                                                
2273                                              continue;                                                             
2274                                          }                                                                         
2275                                      }                                                                             
2276                                                                                                                    
2277                                      appWidgetInfo.id = id;                                                        
2278                                      appWidgetInfo.screenId = c.getInt(screenIndex);                               
2279                                      appWidgetInfo.cellX = c.getInt(cellXIndex);                                   
2280                                      appWidgetInfo.cellY = c.getInt(cellYIndex);                                   
2281                                      appWidgetInfo.spanX = c.getInt(spanXIndex);                                   
2282                                      appWidgetInfo.spanY = c.getInt(spanYIndex);                                   
2283                                                                                                                    
2284                                      if (!customWidget) {                                                          
2285                                          int[] minSpan = Launcher.getMinSpanForWidget(context, provider);          
2286                                          appWidgetInfo.minSpanX = minSpan[0];                                      
2287                                          appWidgetInfo.minSpanY = minSpan[1];                                      
2288                                      }                                                                             
2289                                                                                                                    
2290                                      container = c.getInt(containerIndex);                                         
2291                                      if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&              
2292                                          container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {              
2293                                          Log.e(TAG, "Widget found where container != " +                           
2294                                              "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");               
2295                                          continue;                                                                 
2296                                      }                                                                             
2297                                                                                                                    
2298                                      appWidgetInfo.container = c.getInt(containerIndex);                           
2299                                      // check & update map of what's occupied                                      
2300                                      if (!checkItemPlacement(occupied, appWidgetInfo)) {                           
2301                                          itemsToRemove.add(id);                                                    
2302                                          break;                                                                    
2303                                      }                                                                             
2304                                                                                                                    
2305                                      if (!customWidget) {                                                          
2306                                          String providerName =                                                     
2307                                                  appWidgetInfo.providerName.flattenToString();                     
2308                                          if (!providerName.equals(savedProvider) ||                                
2309                                                  (appWidgetInfo.restoreStatus != restoreStatus)) {                 
2310                                              ContentValues values = new ContentValues();                           
2311                                              values.put(                                                           
2312                                                      LauncherSettings.Favorites.APPWIDGET_PROVIDER,                
2313                                                      providerName);                                                
2314                                              values.put(LauncherSettings.Favorites.RESTORED,                       
2315                                                      appWidgetInfo.restoreStatus);                                 
2316                                              updateItem(id, values);                                               
2317                                          }                                                                         
2318                                      }                                                                             
2319                                      sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                           
2320                                      sBgAppWidgets.add(appWidgetInfo);                                             
2321                                  }                                                                                 
2322                                  break;                                                                            
2323                              }                                                                                     
2324                          } catch (Exception e) {                                                                   
2325                              Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);               
2326                          }                                                                                         
2327                      }                                                                                             
2328                  } finally {                                                                                       
2329                      if (c != null) {                                                                              
2330                          c.close();                                                                                
2331                      }                                                                                             
2332                  }                                                                                                 
2333                                                                                                                    
2334                  // Break early if we've stopped loading                                                           
2335                  if (mStopped) {                                                                                   
2336                      clearSBgDataStructures();                                                                     
2337                      return;                                                                                       
2338                  }                                                                                                 
2339                                                                                                                    
2340                  if (itemsToRemove.size() > 0) {                                                                   
2341                      ContentProviderClient client = contentResolver.acquireContentProviderClient(                  
2342                              contentUri);                                                                          
2343                      // Remove dead items                                                                          
2344                      for (long id : itemsToRemove) {                                                               
2345                          if (DEBUG_LOADERS) {                                                                      
2346                              Log.d(TAG, "Removed id = " + id);                                                     
2347                          }                                                                                         
2348                          // Don't notify content observers                                                         
2349                          try {                                                                                     
2350                              client.delete(LauncherSettings.Favorites.getContentUri(id, false),                    
2351                                      null, null);                                                                  
2352                          } catch (RemoteException e) {                                                             
2353                              Log.w(TAG, "Could not remove id = " + id);                                            
2354                          }                                                                                         
2355                      }                                                                                             
2356                  }                                                                                                 
2357                                                                                                                    
2358                  if (restoredRows.size() > 0) {                                                                    
2359                      ContentProviderClient updater = contentResolver.acquireContentProviderClient(                 
2360                              contentUri);                                                                          
2361                      // Update restored items that no longer require special handling                              
2362                      try {                                                                                         
2363                          StringBuilder selectionBuilder = new StringBuilder();                                     
2364                          selectionBuilder.append(LauncherSettings.Favorites._ID);                                  
2365                          selectionBuilder.append(" IN (");                                                         
2366                          selectionBuilder.append(TextUtils.join(", ", restoredRows));                              
2367                          selectionBuilder.append(")");                                                             
2368                          ContentValues values = new ContentValues();                                               
2369                          values.put(LauncherSettings.Favorites.RESTORED, 0);                                       
2370                          updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                    
2371                                  values, selectionBuilder.toString(), null);                                       
2372                      } catch (RemoteException e) {                                                                 
2373                          Log.w(TAG, "Could not update restored rows");                                             
2374                      }                                                                                             
2375                  }                                                                                                 
2376                                                                                                                    
2377                  if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                              
2378                      context.registerReceiver(new AppsAvailabilityCheck(),                                         
2379                              new IntentFilter(StartupReceiver.SYSTEM_READY),                                       
2380                              null, sWorker);                                                                       
2381                  }                                                                                                 
2382                                                                                                                    
2383                  sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                                     
2384                  // Log to disk                                                                                    
2385                  Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                                   
2386                          TextUtils.join(", ", sBgWorkspaceScreens), true);                                         
2387                                                                                                                    
2388                  // Remove any empty screens                                                                       
2389                  ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                         
2390                  for (ItemInfo item: sBgItemsIdMap.values()) {                                                     
2391                      long screenId = item.screenId;                                                                
2392                      if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                         
2393                              unusedScreens.contains(screenId)) {                                                   
2394                          unusedScreens.remove(screenId);                                                           
2395                      }                                                                                             
2396                  }                                                                                                 
2397                                                                                                                    
2398                  // If there are any empty screens remove them, and update.                                        
2399                  if (unusedScreens.size() != 0) {                                                                  
2400                      // Log to disk                                                                                
2401                      Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +                     
2402                              TextUtils.join(", ", unusedScreens), true);                                           
2403                                                                                                                    
2404                      sBgWorkspaceScreens.removeAll(unusedScreens);                                                 
2405                      updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                     
2406                  }                                                                                                 
2407                                                                                                                    
2408                  if (DEBUG_LOADERS) {                                                                              
2409                      Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");                   
2410                      Log.d(TAG, "workspace layout: ");                                                             
2411                      int nScreens = occupied.size();                                                               
2412                      for (int y = 0; y < countY; y++) {                                                            
2413                          String line = "";                                                                         
2414                                                                                                                    
2415                          Iterator<Long> iter = occupied.keySet().iterator();                                       
2416                          while (iter.hasNext()) {                                                                  
2417                              long screenId = iter.next();                                                          
2418                              if (screenId > 0) {                                                                   
2419                                  line += " | ";                                                                    
2420                              }                                                                                     
2421                              for (int x = 0; x < countX; x++) {                                                    
2422                                  ItemInfo[][] screen = occupied.get(screenId);                                     
2423                                  if (x < screen.length && y < screen[x].length) {                                  
2424                                      line += (screen[x][y] != null) ? "#" : ".";                                   
2425                                  } else {                                                                          
2426                                      line += "!";                                                                  
2427                                  }                                                                                 
2428                              }                                                                                     
2429                          }                                                                                         
2430                          Log.d(TAG, "[ " + line + " ]");                                                           
2431                      }                                                                                             
2432                  }                                                                                                 
2433              }                                                                                                     
2434          }                                                                                                         
2435                                                                                                                    
2436          /**                                                                                                       
2437           * Partially updates the item without any notification. Must be called on the worker thread.              
2438           */                                                                                                       
2439          private void updateItem(long itemId, ContentValues update) {                                              
2440              mContext.getContentResolver().update(                                                                 
2441                      LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                       
2442                      update,                                                                                       
2443                      BaseColumns._ID + "= ?",                                                                      
2444                      new String[]{Long.toString(itemId)});                                                         
2445          }                                                                                                         
2446                                                                                                                    
2447          /** Filters the set of items who are directly or indirectly (via another container) on the                
2448           * specified screen. */                                                                                   
2449          private void filterCurrentWorkspaceItems(long currentScreenId,                                            
2450                  ArrayList<ItemInfo> allWorkspaceItems,                                                            
2451                  ArrayList<ItemInfo> currentScreenItems,                                                           
2452                  ArrayList<ItemInfo> otherScreenItems) {                                                           
2453              // Purge any null ItemInfos                                                                           
2454              Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                               
2455              while (iter.hasNext()) {                                                                              
2456                  ItemInfo i = iter.next();                                                                         
2457                  if (i == null) {                                                                                  
2458                      iter.remove();                                                                                
2459                  }                                                                                                 
2460              }                                                                                                     
2461                                                                                                                    
2462              // Order the set of items by their containers first, this allows use to walk through the              
2463              // list sequentially, build up a list of containers that are in the specified screen,                 
2464              // as well as all items in those containers.                                                          
2465              Set<Long> itemsOnScreen = new HashSet<Long>();                                                        
2466              Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                                      
2467                  @Override                                                                                         
2468                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2469                      return (int) (lhs.container - rhs.container);                                                 
2470                  }                                                                                                 
2471              });                                                                                                   
2472              for (ItemInfo info : allWorkspaceItems) {                                                             
2473                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
2474                      if (info.screenId == currentScreenId) {                                                       
2475                          currentScreenItems.add(info);                                                             
2476                          itemsOnScreen.add(info.id);                                                               
2477                      } else {                                                                                      
2478                          otherScreenItems.add(info);                                                               
2479                      }                                                                                             
2480                  } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                      
2481                      currentScreenItems.add(info);                                                                 
2482                      itemsOnScreen.add(info.id);                                                                   
2483                  } else {                                                                                          
2484                      if (itemsOnScreen.contains(info.container)) {                                                 
2485                          currentScreenItems.add(info);                                                             
2486                          itemsOnScreen.add(info.id);                                                               
2487                      } else {                                                                                      
2488                          otherScreenItems.add(info);                                                               
2489                      }                                                                                             
2490                  }                                                                                                 
2491              }                                                                                                     
2492          }                                                                                                         
2493                                                                                                                    
2494          /** Filters the set of widgets which are on the specified screen. */                                      
2495          private void filterCurrentAppWidgets(long currentScreenId,                                                
2496                  ArrayList<LauncherAppWidgetInfo> appWidgets,                                                      
2497                  ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                            
2498                  ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                            
2499                                                                                                                    
2500              for (LauncherAppWidgetInfo widget : appWidgets) {                                                     
2501                  if (widget == null) continue;                                                                     
2502                  if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                           
2503                          widget.screenId == currentScreenId) {                                                     
2504                      currentScreenWidgets.add(widget);                                                             
2505                  } else {                                                                                          
2506                      otherScreenWidgets.add(widget);                                                               
2507                  }                                                                                                 
2508              }                                                                                                     
2509          }                                                                                                         
2510                                                                                                                    
2511          /** Filters the set of folders which are on the specified screen. */                                      
2512          private void filterCurrentFolders(long currentScreenId,                                                   
2513                  HashMap<Long, ItemInfo> itemsIdMap,                                                               
2514                  HashMap<Long, FolderInfo> folders,                                                                
2515                  HashMap<Long, FolderInfo> currentScreenFolders,                                                   
2516                  HashMap<Long, FolderInfo> otherScreenFolders) {                                                   
2517                                                                                                                    
2518              for (long id : folders.keySet()) {                                                                    
2519                  ItemInfo info = itemsIdMap.get(id);                                                               
2520                  FolderInfo folder = folders.get(id);                                                              
2521                  if (info == null || folder == null) continue;                                                     
2522                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                             
2523                          info.screenId == currentScreenId) {                                                       
2524                      currentScreenFolders.put(id, folder);                                                         
2525                  } else {                                                                                          
2526                      otherScreenFolders.put(id, folder);                                                           
2527                  }                                                                                                 
2528              }                                                                                                     
2529          }                                                                                                         
2530                                                                                                                    
2531          /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to                   
2532           * right) */                                                                                              
2533          private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                            
2534              final LauncherAppState app = LauncherAppState.getInstance();                                          
2535              final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                   
2536              // XXX: review this                                                                                   
2537              Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                         
2538                  @Override                                                                                         
2539                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2540                      int cellCountX = (int) grid.numColumns;                                                       
2541                      int cellCountY = (int) grid.numRows;                                                          
2542                      int screenOffset = cellCountX * cellCountY;                                                   
2543                      int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat               
2544                      long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +                    
2545                              lhs.cellY * cellCountX + lhs.cellX);                                                  
2546                      long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +                    
2547                              rhs.cellY * cellCountX + rhs.cellX);                                                  
2548                      return (int) (lr - rr);                                                                       
2549                  }                                                                                                 
2550              });                                                                                                   
2551          }                                                                                                         
2552                                                                                                                    
2553          private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                           
2554                  final ArrayList<Long> orderedScreens) {                                                           
2555              final Runnable r = new Runnable() {                                                                   
2556                  @Override                                                                                         
2557                  public void run() {                                                                               
2558                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2559                      if (callbacks != null) {                                                                      
2560                          callbacks.bindScreens(orderedScreens);                                                    
2561                      }                                                                                             
2562                  }                                                                                                 
2563              };                                                                                                    
2564              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2565          }                                                                                                         
2566                                                                                                                    
2567          private void bindWorkspaceItems(final Callbacks oldCallbacks,                                             
2568                  final ArrayList<ItemInfo> workspaceItems,                                                         
2569                  final ArrayList<LauncherAppWidgetInfo> appWidgets,                                                
2570                  final HashMap<Long, FolderInfo> folders,                                                          
2571                  ArrayList<Runnable> deferredBindRunnables) {                                                      
2572                                                                                                                    
2573              final boolean postOnMainThread = (deferredBindRunnables != null);                                     
2574                                                                                                                    
2575              // Bind the workspace items                                                                           
2576              int N = workspaceItems.size();                                                                        
2577              for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                            
2578                  final int start = i;                                                                              
2579                  final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                                 
2580                  final Runnable r = new Runnable() {                                                               
2581                      @Override                                                                                     
2582                      public void run() {                                                                           
2583                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2584                          if (callbacks != null) {                                                                  
2585                              callbacks.bindItems(workspaceItems, start, start+chunkSize,                           
2586                                      false);                                                                       
2587                          }                                                                                         
2588                      }                                                                                             
2589                  };                                                                                                
2590                  if (postOnMainThread) {                                                                           
2591                      synchronized (deferredBindRunnables) {                                                        
2592                          deferredBindRunnables.add(r);                                                             
2593                      }                                                                                             
2594                  } else {                                                                                          
2595                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2596                  }                                                                                                 
2597              }                                                                                                     
2598                                                                                                                    
2599              // Bind the folders                                                                                   
2600              if (!folders.isEmpty()) {                                                                             
2601                  final Runnable r = new Runnable() {                                                               
2602                      public void run() {                                                                           
2603                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2604                          if (callbacks != null) {                                                                  
2605                              callbacks.bindFolders(folders);                                                       
2606                          }                                                                                         
2607                      }                                                                                             
2608                  };                                                                                                
2609                  if (postOnMainThread) {                                                                           
2610                      synchronized (deferredBindRunnables) {                                                        
2611                          deferredBindRunnables.add(r);                                                             
2612                      }                                                                                             
2613                  } else {                                                                                          
2614                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2615                  }                                                                                                 
2616              }                                                                                                     
2617                                                                                                                    
2618              // Bind the widgets, one at a time                                                                    
2619              N = appWidgets.size();                                                                                
2620              for (int i = 0; i < N; i++) {                                                                         
2621                  final LauncherAppWidgetInfo widget = appWidgets.get(i);                                           
2622                  final Runnable r = new Runnable() {                                                               
2623                      public void run() {                                                                           
2624                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2625                          if (callbacks != null) {                                                                  
2626                              callbacks.bindAppWidget(widget);                                                      
2627                          }                                                                                         
2628                      }                                                                                             
2629                  };                                                                                                
2630                  if (postOnMainThread) {                                                                           
2631                      deferredBindRunnables.add(r);                                                                 
2632                  } else {                                                                                          
2633                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2634                  }                                                                                                 
2635              }                                                                                                     
2636          }                                                                                                         
2637                                                                                                                    
2638          /**                                                                                                       
2639           * Binds all loaded data to actual views on the main thread.                                              
2640           */                                                                                                       
2641          private void bindWorkspace(int synchronizeBindPage) {                                                     
2642              final long t = SystemClock.uptimeMillis();                                                            
2643              Runnable r;                                                                                           
2644                                                                                                                    
2645              // Don't use these two variables in any of the callback runnables.                                    
2646              // Otherwise we hold a reference to them.                                                             
2647              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2648              if (oldCallbacks == null) {                                                                           
2649                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2650                  Log.w(TAG, "LoaderTask running with no launcher");                                                
2651                  return;                                                                                           
2652              }                                                                                                     
2653                                                                                                                    
2654              // Save a copy of all the bg-thread collections                                                       
2655              ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                                       
2656              ArrayList<LauncherAppWidgetInfo> appWidgets =                                                         
2657                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2658              HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                                  
2659              HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                                   
2660              ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                             
2661              synchronized (sBgLock) {                                                                              
2662                  workspaceItems.addAll(sBgWorkspaceItems);                                                         
2663                  appWidgets.addAll(sBgAppWidgets);                                                                 
2664                  folders.putAll(sBgFolders);                                                                       
2665                  itemsIdMap.putAll(sBgItemsIdMap);                                                                 
2666                  orderedScreenIds.addAll(sBgWorkspaceScreens);                                                     
2667              }                                                                                                     
2668                                                                                                                    
2669              final boolean isLoadingSynchronously =                                                                
2670                      synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                                        
2671              int currScreen = isLoadingSynchronously ? synchronizeBindPage :                                       
2672                  oldCallbacks.getCurrentWorkspaceScreen();                                                         
2673              if (currScreen >= orderedScreenIds.size()) {                                                          
2674                  // There may be no workspace screens (just hotseat items and an empty page).                      
2675                  currScreen = PagedView.INVALID_RESTORE_PAGE;                                                      
2676              }                                                                                                     
2677              final int currentScreen = currScreen;                                                                 
2678              final long currentScreenId = currentScreen < 0                                                        
2679                      ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                                    
2680                                                                                                                    
2681              // Load all the items that are on the current page first (and in the process, unbind                  
2682              // all the existing workspace items before we call startBinding() below.                              
2683              unbindWorkspaceItemsOnMainThread();                                                                   
2684                                                                                                                    
2685              // Separate the items that are on the current screen, and all the other remaining items               
2686              ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                                
2687              ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                                  
2688              ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                                  
2689                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2690              ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                                    
2691                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2692              HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                           
2693              HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                             
2694                                                                                                                    
2695              filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,                   
2696                      otherWorkspaceItems);                                                                         
2697              filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                               
2698                      otherAppWidgets);                                                                             
2699              filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                            
2700                      otherFolders);                                                                                
2701              sortWorkspaceItemsSpatially(currentWorkspaceItems);                                                   
2702              sortWorkspaceItemsSpatially(otherWorkspaceItems);                                                     
2703                                                                                                                    
2704              // Tell the workspace that we're about to start binding items                                         
2705              r = new Runnable() {                                                                                  
2706                  public void run() {                                                                               
2707                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2708                      if (callbacks != null) {                                                                      
2709                          callbacks.startBinding();                                                                 
2710                      }                                                                                             
2711                  }                                                                                                 
2712              };                                                                                                    
2713              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2714                                                                                                                    
2715              bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                                 
2716                                                                                                                    
2717              // Load items on the current page                                                                     
2718              bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                            
2719                      currentFolders, null);                                                                        
2720              if (isLoadingSynchronously) {                                                                         
2721                  r = new Runnable() {                                                                              
2722                      public void run() {                                                                           
2723                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2724                          if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {               
2725                              callbacks.onPageBoundSynchronously(currentScreen);                                    
2726                          }                                                                                         
2727                      }                                                                                             
2728                  };                                                                                                
2729                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2730              }                                                                                                     
2731                                                                                                                    
2732              // Load all the remaining pages (if we are loading synchronously, we want to defer this               
2733              // work until after the first render)                                                                 
2734              synchronized (mDeferredBindRunnables) {                                                               
2735                  mDeferredBindRunnables.clear();                                                                   
2736              }                                                                                                     
2737              bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                  
2738                      (isLoadingSynchronously ? mDeferredBindRunnables : null));                                    
2739                                                                                                                    
2740              // Tell the workspace that we're done binding items                                                   
2741              r = new Runnable() {                                                                                  
2742                  public void run() {                                                                               
2743                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2744                      if (callbacks != null) {                                                                      
2745                          callbacks.finishBindingItems();                                                           
2746                      }                                                                                             
2747                                                                                                                    
2748                      // If we're profiling, ensure this is the last thing in the queue.                            
2749                      if (DEBUG_LOADERS) {                                                                          
2750                          Log.d(TAG, "bound workspace in "                                                          
2751                              + (SystemClock.uptimeMillis()-t) + "ms");                                             
2752                      }                                                                                             
2753                                                                                                                    
2754                      mIsLoadingAndBindingWorkspace = false;                                                        
2755                  }                                                                                                 
2756              };                                                                                                    
2757              if (isLoadingSynchronously) {                                                                         
2758                  synchronized (mDeferredBindRunnables) {                                                           
2759                      mDeferredBindRunnables.add(r);                                                                
2760                  }                                                                                                 
2761              } else {                                                                                              
2762                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2763              }                                                                                                     
2764          }                                                                                                         
2765                                                                                                                    
2766          private void loadAndBindAllApps() {                                                                       
2767              if (DEBUG_LOADERS) {                                                                                  
2768                  Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                                
2769              }                                                                                                     
2770              if (!mAllAppsLoaded) {                                                                                
2771                  loadAllApps();                                                                                    
2772                  synchronized (LoaderTask.this) {                                                                  
2773                      if (mStopped) {                                                                               
2774                          return;                                                                                   
2775                      }                                                                                             
2776                      mAllAppsLoaded = true;                                                                        
2777                  }                                                                                                 
2778              } else {                                                                                              
2779                  onlyBindAllApps();                                                                                
2780              }                                                                                                     
2781          }                                                                                                         
2782                                                                                                                    
2783          private void onlyBindAllApps() {                                                                          
2784              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2785              if (oldCallbacks == null) {                                                                           
2786                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2787                  Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                              
2788                  return;                                                                                           
2789              }                                                                                                     
2790                                                                                                                    
2791              // shallow copy                                                                                       
2792              @SuppressWarnings("unchecked")                                                                        
2793              final ArrayList<AppInfo> list                                                                         
2794                      = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                           
2795              Runnable r = new Runnable() {                                                                         
2796                  public void run() {                                                                               
2797                      final long t = SystemClock.uptimeMillis();                                                    
2798                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2799                      if (callbacks != null) {                                                                      
2800                          callbacks.bindAllApplications(list);                                                      
2801                      }                                                                                             
2802                      if (DEBUG_LOADERS) {                                                                          
2803                          Log.d(TAG, "bound all " + list.size() + " apps from cache in "                            
2804                                  + (SystemClock.uptimeMillis()-t) + "ms");                                         
2805                      }                                                                                             
2806                  }                                                                                                 
2807              };                                                                                                    
2808              boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());                    
2809              if (isRunningOnMainThread) {                                                                          
2810                  r.run();                                                                                          
2811              } else {                                                                                              
2812                  mHandler.post(r);                                                                                 
2813              }                                                                                                     
2814          }                                                                                                         
2815                                                                                                                    
2816          private void loadAllApps() {                                                                              
2817              final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2818                                                                                                                    
2819              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2820              if (oldCallbacks == null) {                                                                           
2821                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2822                  Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                                  
2823                  return;                                                                                           
2824              }                                                                                                     
2825                                                                                                                    
2826              final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                                       
2827              mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                     
2828                                                                                                                    
2829              final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                               
2830                                                                                                                    
2831              // Clear the list of apps                                                                             
2832              mBgAllAppsList.clear();                                                                               
2833              SharedPreferences prefs = mContext.getSharedPreferences(                                              
2834                      LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                            
2835              for (UserHandleCompat user : profiles) {                                                              
2836                  // Query for the set of apps                                                                      
2837                  final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                              
2838                  List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);                
2839                  if (DEBUG_LOADERS) {                                                                              
2840                      Log.d(TAG, "getActivityList took "                                                            
2841                              + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);                      
2842                      Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);                  
2843                  }                                                                                                 
2844                  // Fail if we don't have any apps                                                                 
2845                  // TODO: Fix this. Only fail for the current user.                                                
2846                  if (apps == null || apps.isEmpty()) {                                                             
2847                      return;                                                                                       
2848                  }                                                                                                 
2849 -                // Sort the applications by name                                                                  
2850 -                final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                             
2851 -                Collections.sort(apps,                                                                            
2852 -                        new LauncherModel.ShortcutNameComparator(mLabelCache));                                   
2853 -                if (DEBUG_LOADERS) {                                                                              
2854 -                    Log.d(TAG, "sort took "                                                                       
2855 -                            + (SystemClock.uptimeMillis()-sortTime) + "ms");                                      
2856 +                                                                                                                  
2857 +                // Update icon cache                                                                              
2858 +                HashSet<String> updatedPackages = mIconCache.updateDBIcons(user, apps);                           
2859 +                                                                                                                  
2860 +                // If any package icon has changed (app was updated while launcher was dead),                     
2861 +                // update the corresponding shortcuts.                                                            
2862 +                if (!updatedPackages.isEmpty()) {                                                                 
2863 +                    final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();                        
2864 +                    synchronized (sBgLock) {                                                                      
2865 +                        for (ItemInfo info : sBgItemsIdMap.values()) {                                            
2866 +                            if (info instanceof ShortcutInfo && user.equals(info.user)                            
2867 +                                    && info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {       
2868 +                                ShortcutInfo si = (ShortcutInfo) info;                                            
2869 +                                ComponentName cn = si.getTargetComponent();                                       
2870 +                                if (cn != null && updatedPackages.contains(cn.getPackageName())) {                
2871 +                                    si.updateIcon(mIconCache);                                                    
2872 +                                    updates.add(si);                                                              
2873 +                                }                                                                                 
2874 +                            }                                                                                     
2875 +                        }                                                                                         
2876 +                    }                                                                                             
2877 +                                                                                                                  
2878 +                    if (!updates.isEmpty()) {                                                                     
2879 +                        final UserHandleCompat userFinal = user;                                                  
2880 +                        mHandler.post(new Runnable() {                                                            
2881 +                                                                                                                  
2882 +                            public void run() {                                                                   
2883 +                                Callbacks cb = getCallback();                                                     
2884 +                                if (cb != null) {                                                                 
2885 +                                    cb.bindShortcutsChanged(                                                      
2886 +                                            updates, new ArrayList<ShortcutInfo>(), userFinal);                   
2887 +                                }                                                                                 
2888 +                            }                                                                                     
2889 +                        });                                                                                       
2890 +                    }                                                                                             
2891                  }                                                                                                 
2892                                                                                                                    
2893                  // Create the ApplicationInfos                                                                    
2894                  for (int i = 0; i < apps.size(); i++) {                                                           
2895                      LauncherActivityInfoCompat app = apps.get(i);                                                 
2896                      // This builds the icon bitmaps.                                                              
2897 -                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));                
2898 +                    mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache));                             
2899                  }                                                                                                 
2900                                                                                                                    
2901                  if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {             
2902                      // Add shortcuts for packages which were installed while launcher was dead.                   
2903                      String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                       
2904                              + mUserManager.getSerialNumberForUser(user);                                          
2905                      Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);       
2906                      HashSet<String> newPackageSet = new HashSet<String>();                                        
2907                                                                                                                    
2908                      for (LauncherActivityInfoCompat info : apps) {                                                
2909                          String packageName = info.getComponentName().getPackageName();                            
2910                          if (!packagesAdded.contains(packageName)                                                  
2911                                  && !newPackageSet.contains(packageName)) {                                        
2912                              InstallShortcutReceiver.queueInstallShortcut(info, mContext);                         
2913                          }                                                                                         
2914                          newPackageSet.add(packageName);                                                           
2915                      }                                                                                             
2916                                                                                                                    
2917                      prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                           
2918                  }                                                                                                 
2919              }                                                                                                     
2920              // Huh? Shouldn't this be inside the Runnable below?                                                  
2921              final ArrayList<AppInfo> added = mBgAllAppsList.added;                                                
2922              mBgAllAppsList.added = new ArrayList<AppInfo>();                                                      
2923                                                                                                                    
2924              // Post callback on main thread                                                                       
2925              mHandler.post(new Runnable() {                                                                        
2926                  public void run() {                                                                               
2927                      final long bindTime = SystemClock.uptimeMillis();                                             
2928                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2929                      if (callbacks != null) {                                                                      
2930                          callbacks.bindAllApplications(added);                                                     
2931                          if (DEBUG_LOADERS) {                                                                      
2932                              Log.d(TAG, "bound " + added.size() + " apps in "                                      
2933                                  + (SystemClock.uptimeMillis() - bindTime) + "ms");                                
2934                          }                                                                                         
2935                      } else {                                                                                      
2936                          Log.i(TAG, "not binding apps: no Launcher activity");                                     
2937                      }                                                                                             
2938                  }                                                                                                 
2939              });                                                                                                   
2940                                                                                                                    
2941              if (DEBUG_LOADERS) {                                                                                  
2942                  Log.d(TAG, "Icons processed in "                                                                  
2943                          + (SystemClock.uptimeMillis() - loadTime) + "ms");                                        
2944              }                                                                                                     
2945          }                                                                                                         
2946                                                                                                                    
2947          public void dumpState() {                                                                                 
2948              synchronized (sBgLock) {                                                                              
2949                  Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                                   
2950                  Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                           
2951                  Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                                   
2952                  Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);                   
2953                  Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                            
2954              }                                                                                                     
2955          }                                                                                                         
2956      }                                                                                                             
2957                                                                                                                    
2958      void enqueuePackageUpdated(PackageUpdatedTask task) {                                                         
2959          sWorker.post(task);                                                                                       
2960      }                                                                                                             
2961                                                                                                                    
2962      private class AppsAvailabilityCheck extends BroadcastReceiver {                                               
2963                                                                                                                    
2964          @Override                                                                                                 
2965          public void onReceive(Context context, Intent intent) {                                                   
2966              synchronized (sBgLock) {                                                                              
2967                  final LauncherAppsCompat launcherApps = LauncherAppsCompat                                        
2968                          .getInstance(mApp.getContext());                                                          
2969                  final PackageManager manager = context.getPackageManager();                                       
2970                  final ArrayList<String> packagesRemoved = new ArrayList<String>();                                
2971                  final ArrayList<String> packagesUnavailable = new ArrayList<String>();                            
2972                  for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {              
2973                      UserHandleCompat user = entry.getKey();                                                       
2974                      packagesRemoved.clear();                                                                      
2975                      packagesUnavailable.clear();                                                                  
2976                      for (String pkg : entry.getValue()) {                                                         
2977                          if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                                
2978                              boolean packageOnSdcard = launcherApps.isAppEnabled(                                  
2979                                      manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);                       
2980                              if (packageOnSdcard) {                                                                
2981                                  Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);               
2982                                  packagesUnavailable.add(pkg);                                                     
2983                              } else {                                                                              
2984                                  Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);                      
2985                                  packagesRemoved.add(pkg);                                                         
2986                              }                                                                                     
2987                          }                                                                                         
2988                      }                                                                                             
2989                      if (!packagesRemoved.isEmpty()) {                                                             
2990                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,                
2991                                  packagesRemoved.toArray(new String[packagesRemoved.size()]), user));              
2992                      }                                                                                             
2993                      if (!packagesUnavailable.isEmpty()) {                                                         
2994                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,           
2995                                  packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));      
2996                      }                                                                                             
2997                  }                                                                                                 
2998                  sPendingPackages.clear();                                                                         
2999              }                                                                                                     
3000          }                                                                                                         
3001      }                                                                                                             
3002                                                                                                                    
3003      private class PackageUpdatedTask implements Runnable {                                                        
3004          int mOp;                                                                                                  
3005          String[] mPackages;                                                                                       
3006          UserHandleCompat mUser;                                                                                   
3007                                                                                                                    
3008          public static final int OP_NONE = 0;                                                                      
3009          public static final int OP_ADD = 1;                                                                       
3010          public static final int OP_UPDATE = 2;                                                                    
3011          public static final int OP_REMOVE = 3; // uninstlled                                                      
3012          public static final int OP_UNAVAILABLE = 4; // external media unmounted                                   
3013                                                                                                                    
3014                                                                                                                    
3015          public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                             
3016              mOp = op;                                                                                             
3017              mPackages = packages;                                                                                 
3018              mUser = user;                                                                                         
3019          }                                                                                                         
3020                                                                                                                    
3021          public void run() {                                                                                       
3022              final Context context = mApp.getContext();                                                            
3023                                                                                                                    
3024              final String[] packages = mPackages;                                                                  
3025              final int N = packages.length;                                                                        
3026              switch (mOp) {                                                                                        
3027                  case OP_ADD:                                                                                      
3028                      for (int i=0; i<N; i++) {                                                                     
3029                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                  
3030 -                        mIconCache.remove(packages[i], mUser);                                                    
3031 +                        mIconCache.updateIconsForPkg(packages[i], mUser);                                         
3032                          mBgAllAppsList.addPackage(context, packages[i], mUser);                                   
3033                      }                                                                                             
3034                                                                                                                    
3035                      // Auto add shortcuts for added packages.                                                     
3036                      if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3037                              && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3038                          SharedPreferences prefs = context.getSharedPreferences(                                   
3039                                  LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3040                          String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3041                                  + mUserManager.getSerialNumberForUser(mUser);                                     
3042                          Set<String> shortcutSet = new HashSet<String>(                                            
3043                                  prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));                       
3044                                                                                                                    
3045                          for (int i=0; i<N; i++) {                                                                 
3046                              if (!shortcutSet.contains(packages[i])) {                                             
3047                                  shortcutSet.add(packages[i]);                                                     
3048                                  List<LauncherActivityInfoCompat> activities =                                     
3049                                          mLauncherApps.getActivityList(packages[i], mUser);                        
3050                                  if (activities != null && !activities.isEmpty()) {                                
3051                                      InstallShortcutReceiver.queueInstallShortcut(                                 
3052                                              activities.get(0), context);                                          
3053                                  }                                                                                 
3054                              }                                                                                     
3055                          }                                                                                         
3056                                                                                                                    
3057                          prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3058                      }                                                                                             
3059                      break;                                                                                        
3060                  case OP_UPDATE:                                                                                   
3061                      for (int i=0; i<N; i++) {                                                                     
3062                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);               
3063 +                        mIconCache.updateIconsForPkg(packages[i], mUser);                                         
3064                          mBgAllAppsList.updatePackage(context, packages[i], mUser);                                
3065                          WidgetPreviewLoader.removePackageFromDb(                                                  
3066                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
3067                      }                                                                                             
3068                      break;                                                                                        
3069                  case OP_REMOVE:                                                                                   
3070                      // Remove the packageName for the set of auto-installed shortcuts. This                       
3071                      // will ensure that the shortcut when the app is installed again.                             
3072                      if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3073                              && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3074                          SharedPreferences prefs = context.getSharedPreferences(                                   
3075                                  LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3076                          String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3077                                  + mUserManager.getSerialNumberForUser(mUser);                                     
3078                          HashSet<String> shortcutSet = new HashSet<String>(                                        
3079                                  prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));                      
3080                          shortcutSet.removeAll(Arrays.asList(mPackages));                                          
3081                          prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3082                      }                                                                                             
3083 +                    for (int i=0; i<N; i++) {                                                                     
3084 +                        if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
3085 +                        mIconCache.removeIconsForPkg(packages[i], mUser);                                         
3086 +                    }                                                                                             
3087                      // Fall through                                                                               
3088                  case OP_UNAVAILABLE:                                                                              
3089 -                    boolean clearCache = mOp == OP_REMOVE;                                                        
3090                      for (int i=0; i<N; i++) {                                                                     
3091                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
3092 -                        mBgAllAppsList.removePackage(packages[i], mUser, clearCache);                             
3093 +                        mBgAllAppsList.removePackage(packages[i], mUser);                                         
3094                          WidgetPreviewLoader.removePackageFromDb(                                                  
3095                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
3096                      }                                                                                             
3097                      break;                                                                                        
3098              }                                                                                                     
3099                                                                                                                    
3100              ArrayList<AppInfo> added = null;                                                                      
3101              ArrayList<AppInfo> modified = null;                                                                   
3102              final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                                      
3103                                                                                                                    
3104              if (mBgAllAppsList.added.size() > 0) {                                                                
3105                  added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                             
3106                  mBgAllAppsList.added.clear();                                                                     
3107              }                                                                                                     
3108              if (mBgAllAppsList.modified.size() > 0) {                                                             
3109                  modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                                       
3110                  mBgAllAppsList.modified.clear();                                                                  
3111              }                                                                                                     
3112              if (mBgAllAppsList.removed.size() > 0) {                                                              
3113                  removedApps.addAll(mBgAllAppsList.removed);                                                       
3114                  mBgAllAppsList.removed.clear();                                                                   
3115              }                                                                                                     
3116                                                                                                                    
3117              final Callbacks callbacks = getCallback();                                                            
3118              if (callbacks == null) {                                                                              
3119                  Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");                   
3120                  return;                                                                                           
3121              }                                                                                                     
3122                                                                                                                    
3123              final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                            
3124                      new HashMap<ComponentName, AppInfo>();                                                        
3125                                                                                                                    
3126              if (added != null) {                                                                                  
3127                  // Ensure that we add all the workspace applications to the db                                    
3128                  if (LauncherAppState.isDisableAllApps()) {                                                        
3129                      final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);                        
3130                      addAndBindAddedWorkspaceApps(context, addedInfos);                                            
3131                  } else {                                                                                          
3132                      addAppsToAllApps(context, added);                                                             
3133                  }                                                                                                 

3134                  for (AppInfo ai : added) {                                                                        
3135                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3136                  }                                                                                                 
3137              }                                                                                                     
3138                                                                                                                    
3139              if (modified != null) {                                                                               
3140                  final ArrayList<AppInfo> modifiedFinal = modified;                                                
3141                  for (AppInfo ai : modified) {                                                                     
3142                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3143                  }                                                                                                 
3144                                                                                                                    
3145                  mHandler.post(new Runnable() {                                                                    
3146                      public void run() {                                                                           
3147                          Callbacks cb = getCallback();                                                             
3148                          if (callbacks == cb && cb != null) {                                                      
3149                              callbacks.bindAppsUpdated(modifiedFinal);                                             
3150                          }                                                                                         
3151                      }                                                                                             
3152                  });                                                                                               
3153              }                                                                                                     
3154                                                                                                                    
3155              // Update shortcut infos                                                                              
3156              if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                              
3157                  final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();                   
3158                  final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();                   
3159                  final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();          
3160                                                                                                                    
3161                  HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));                        
3162                  synchronized (sBgLock) {                                                                          
3163                      for (ItemInfo info : sBgItemsIdMap.values()) {                                                
3164                          if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                            
3165                              ShortcutInfo si = (ShortcutInfo) info;                                                
3166                              boolean infoUpdated = false;                                                          
3167                              boolean shortcutUpdated = false;                                                      
3168                                                                                                                    
3169                              // Update shortcuts which use iconResource.                                           
3170                              if ((si.iconResource != null)                                                         
3171                                      && packageSet.contains(si.iconResource.packageName)) {                        
3172                                  Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,             
3173                                          si.iconResource.resourceName, mIconCache, context);                       
3174                                  if (icon != null) {                                                               
3175                                      si.setIcon(icon);                                                             
3176                                      si.usingFallbackIcon = false;                                                 
3177                                      infoUpdated = true;                                                           
3178                                  }                                                                                 
3179                              }                                                                                     
3180                                                                                                                    
3181                              ComponentName cn = si.getTargetComponent();                                           
3182                              if (cn != null && packageSet.contains(cn.getPackageName())) {                         
3183                                  AppInfo appInfo = addedOrUpdatedApps.get(cn);                                     
3184                                                                                                                    
3185                                  if (si.isPromise()) {                                                             
3186 -                                    mIconCache.deletePreloadedIcon(cn, mUser);                                    
3187                                      if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                    
3188                                          // Auto install icon                                                      
3189                                          PackageManager pm = context.getPackageManager();                          
3190                                          ResolveInfo matched = pm.resolveActivity(                                 
3191                                                  new Intent(Intent.ACTION_MAIN)                                    
3192                                                  .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),          
3193                                                  PackageManager.MATCH_DEFAULT_ONLY);                               
3194                                          if (matched == null) {                                                    
3195                                              // Try to find the best match activity.                               
3196                                              Intent intent = pm.getLaunchIntentForPackage(                         
3197                                                      cn.getPackageName());                                         
3198                                              if (intent != null) {                                                 
3199                                                  cn = intent.getComponent();                                       
3200                                                  appInfo = addedOrUpdatedApps.get(cn);                             
3201                                              }                                                                     
3202                                                                                                                    
3203                                              if ((intent == null) || (appInfo == null)) {                          
3204                                                  removedShortcuts.add(si);                                         
3205                                                  continue;                                                         
3206                                              }                                                                     
3207                                              si.promisedIntent = intent;                                           
3208                                          }                                                                         
3209                                      }                                                                             
3210                                                                                                                    
3211                                      // Restore the shortcut.                                                      
3212                                      si.intent = si.promisedIntent;                                                
3213                                      si.promisedIntent = null;                                                     
3214                                      si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                                 
3215                                              & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                  
3216                                              & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                          
3217                                                                                                                    
3218                                      infoUpdated = true;                                                           
3219                                      si.updateIcon(mIconCache);                                                    
3220                                  }                                                                                 
3221                                                                                                                    
3222                                  if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())           
3223                                          && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {     
3224                                      si.updateIcon(mIconCache);                                                    
3225                                      si.title = appInfo.title.toString();                                          
3226                                      si.contentDescription = appInfo.contentDescription;                           
3227                                      infoUpdated = true;                                                           
3228                                  }                                                                                 
3229                                                                                                                    
3230                                  if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {            
3231                                      // Since package was just updated, the target must be available now.          
3232                                      si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                   
3233                                      shortcutUpdated = true;                                                       
3234                                  }                                                                                 
3235                              }                                                                                     
3236                                                                                                                    
3237                              if (infoUpdated || shortcutUpdated) {                                                 
3238                                  updatedShortcuts.add(si);                                                         
3239                              }                                                                                     
3240                              if (infoUpdated) {                                                                    
3241                                  updateItemInDatabase(context, si);                                                
3242                              }                                                                                     
3243                          } else if (info instanceof LauncherAppWidgetInfo) {                                       
3244                              LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                      
3245                              if (mUser.equals(widgetInfo.user)                                                     
3246                                      && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)   
3247                                      && packageSet.contains(widgetInfo.providerName.getPackageName())) {           
3248                                  widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;       
3249                                  widgets.add(widgetInfo);                                                          
3250                                  updateItemInDatabase(context, widgetInfo);                                        
3251                              }                                                                                     
3252                          }                                                                                         
3253                      }                                                                                             
3254                  }                                                                                                 
3255                                                                                                                    
3256                  if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                                 
3257                      mHandler.post(new Runnable() {                                                                
3258                                                                                                                    
3259                          public void run() {                                                                       
3260                              Callbacks cb = getCallback();                                                         
3261                              if (callbacks == cb && cb != null) {                                                  
3262                                  callbacks.bindShortcutsChanged(                                                   
3263                                          updatedShortcuts, removedShortcuts, mUser);                               
3264                              }                                                                                     
3265                          }                                                                                         
3266                      });                                                                                           
3267                      if (!removedShortcuts.isEmpty()) {                                                            
3268                          deleteItemsFromDatabase(context, removedShortcuts);                                       
3269                      }                                                                                             
3270                  }                                                                                                 
3271                  if (!widgets.isEmpty()) {                                                                         
3272                      mHandler.post(new Runnable() {                                                                
3273                          public void run() {                                                                       
3274                              Callbacks cb = getCallback();                                                         
3275                              if (callbacks == cb && cb != null) {                                                  
3276                                  callbacks.bindWidgetsRestored(widgets);                                           
3277                              }                                                                                     
3278                          }                                                                                         
3279                      });                                                                                           
3280                  }                                                                                                 
3281              }                                                                                                     
3282                                                                                                                    
3283              final ArrayList<String> removedPackageNames =                                                         
3284                      new ArrayList<String>();                                                                      
3285              if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                                      
3286                  // Mark all packages in the broadcast to be removed                                               
3287                  removedPackageNames.addAll(Arrays.asList(packages));                                              
3288              } else if (mOp == OP_UPDATE) {                                                                        
3289                  // Mark disabled packages in the broadcast to be removed                                          
3290                  for (int i=0; i<N; i++) {                                                                         
3291                      if (isPackageDisabled(context, packages[i], mUser)) {                                         
3292                          removedPackageNames.add(packages[i]);                                                     
3293                      }                                                                                             
3294                  }                                                                                                 
3295              }                                                                                                     
3296                                                                                                                    
3297              if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                                       
3298                  final int removeReason;                                                                           
3299                  if (mOp == OP_UNAVAILABLE) {                                                                      
3300                      removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                                      
3301                  } else {                                                                                          
3302                      // Remove all the components associated with this package                                     
3303                      for (String pn : removedPackageNames) {                                                       
3304                          deletePackageFromDatabase(context, pn, mUser);                                            
3305                      }                                                                                             
3306                      // Remove all the specific components                                                         
3307                      for (AppInfo a : removedApps) {                                                               
3308                          ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);          
3309                          deleteItemsFromDatabase(context, infos);                                                  
3310                      }                                                                                             
3311                      removeReason = 0;                                                                             
3312                  }                                                                                                 
3313                                                                                                                    
3314                  // Remove any queued items from the install queue                                                 
3315                  InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);              
3316                  // Call the components-removed callback                                                           
3317                  mHandler.post(new Runnable() {                                                                    
3318                      public void run() {                                                                           
3319                          Callbacks cb = getCallback();                                                             
3320                          if (callbacks == cb && cb != null) {                                                      
3321                              callbacks.bindComponentsRemoved(                                                      
3322                                      removedPackageNames, removedApps, mUser, removeReason);                       
3323                          }                                                                                         
3324                      }                                                                                             
3325                  });                                                                                               
3326              }                                                                                                     
3327                                                                                                                    
3328              final ArrayList<Object> widgetsAndShortcuts =                                                         
3329                      getSortedWidgetsAndShortcuts(context);                                                        
3330              mHandler.post(new Runnable() {                                                                        
3331                  @Override                                                                                         
3332                  public void run() {                                                                               
3333                      Callbacks cb = getCallback();                                                                 
3334                      if (callbacks == cb && cb != null) {                                                          
3335                          callbacks.bindPackagesUpdated(widgetsAndShortcuts);                                       
3336                      }                                                                                             
3337                  }                                                                                                 
3338              });                                                                                                   
3339                                                                                                                    
3340              // Write all the logs to disk                                                                         
3341              mHandler.post(new Runnable() {                                                                        
3342                  public void run() {                                                                               
3343                      Callbacks cb = getCallback();                                                                 
3344                      if (callbacks == cb && cb != null) {                                                          
3345                          callbacks.dumpLogsToLocalData();                                                          
3346                      }                                                                                             
3347                  }                                                                                                 
3348              });                                                                                                   
3349          }                                                                                                         
3350      }                                                                                                             
3351                                                                                                                    
3352      public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context) {                       
3353          synchronized (sBgLock) {                                                                                  
3354              if (sBgWidgetProviders != null && !sWidgetProvidersDirty) {                                           
3355                  return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());                 
3356              }                                                                                                     
3357              sBgWidgetProviders = new HashMap<ComponentName, LauncherAppWidgetProviderInfo>();                     
3358              List<AppWidgetProviderInfo> widgets =                                                                 
3359                      AppWidgetManagerCompat.getInstance(context).getAllProviders();                                
3360              LauncherAppWidgetProviderInfo info;                                                                   
3361              for (AppWidgetProviderInfo pInfo : widgets) {                                                         
3362                  info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                            
3363                  sBgWidgetProviders.put(info.provider, info);                                                      
3364              }                                                                                                     
3365                                                                                                                    
3366              Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();                  
3367              for (CustomAppWidget widget : customWidgets) {                                                        
3368                  info = new LauncherAppWidgetProviderInfo(context, widget);                                        
3369                  sBgWidgetProviders.put(info.provider, info);                                                      
3370              }                                                                                                     
3371              sWidgetProvidersDirty = false;                                                                        
3372              return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());                     
3373          }                                                                                                         
3374      }                                                                                                             
3375                                                                                                                    
3376      public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {                
3377          synchronized (sBgLock) {                                                                                  
3378              if (sBgWidgetProviders == null) {                                                                     
3379                  getWidgetProviders(ctx);                                                                          
3380              }                                                                                                     
3381              return sBgWidgetProviders.get(name);                                                                  
3382          }                                                                                                         
3383      }                                                                                                             
3384                                                                                                                    
3385      // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                              
3386      public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                               
3387          PackageManager packageManager = context.getPackageManager();                                              
3388          final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                                    
3389          widgetsAndShortcuts.addAll(getWidgetProviders(context));                                                  
3390          Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                                       
3391          widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));                     
3392          Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));                      
3393          return widgetsAndShortcuts;                                                                               
3394      }                                                                                                             
3395                                                                                                                    
3396      private static boolean isPackageDisabled(Context context, String packageName,                                 
3397              UserHandleCompat user) {                                                                              
3398          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3399          return !launcherApps.isPackageEnabledForProfile(packageName, user);                                       
3400      }                                                                                                             
3401                                                                                                                    
3402      public static boolean isValidPackageActivity(Context context, ComponentName cn,                               
3403              UserHandleCompat user) {                                                                              
3404          if (cn == null) {                                                                                         
3405              return false;                                                                                         
3406          }                                                                                                         
3407          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3408          if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                                
3409              return false;                                                                                         
3410          }                                                                                                         
3411          return launcherApps.isActivityEnabledForProfile(cn, user);                                                
3412      }                                                                                                             
3413                                                                                                                    
3414      public static boolean isValidPackage(Context context, String packageName,                                     
3415              UserHandleCompat user) {                                                                              
3416          if (packageName == null) {                                                                                
3417              return false;                                                                                         
3418          }                                                                                                         
3419          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3420          return launcherApps.isPackageEnabledForProfile(packageName, user);                                        
3421      }                                                                                                             
3422                                                                                                                    
3423      /**                                                                                                           
3424       * Make an ShortcutInfo object for a restored application or shortcut item that points                        
3425       * to a package that is not yet installed on the system.                                                      
3426       */                                                                                                           
3427      public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,                         
3428              int promiseType) {                                                                                    
3429          final ShortcutInfo info = new ShortcutInfo();                                                             
3430          info.user = UserHandleCompat.myUserHandle();                                                              
3431 -        mIconCache.getTitleAndIcon(info, intent, info.user, true);                                                
3432 +        mIconCache.getTitleAndIcon(info, intent, info.user);                                                      
3433                                                                                                                    
3434          if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                               
3435              String title = (cursor != null) ? cursor.getString(titleIndex) : null;                                
3436              if (!TextUtils.isEmpty(title)) {                                                                      
3437                  info.title = title;                                                                               
3438              }                                                                                                     
3439              info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                                        
3440          } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                                     
3441              if (TextUtils.isEmpty(info.title)) {                                                                  
3442                  info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                                
3443              }                                                                                                     
3444              info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                                      
3445          } else {                                                                                                  
3446              throw new InvalidParameterException("Invalid restoreType " + promiseType);                            
3447          }                                                                                                         
3448                                                                                                                    
3449          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3450                  info.title.toString(), info.user);                                                                
3451          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3452          info.promisedIntent = intent;                                                                             
3453          return info;                                                                                              
3454      }                                                                                                             
3455                                                                                                                    
3456      /**                                                                                                           
3457       * Make an Intent object for a restored application or shortcut item that points                              
3458       * to the market page for the item.                                                                           
3459       */                                                                                                           
3460      private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                              
3461          ComponentName componentName = intent.getComponent();                                                      
3462          return getMarketIntent(componentName.getPackageName());                                                   
3463      }                                                                                                             
3464                                                                                                                    
3465      static Intent getMarketIntent(String packageName) {                                                           
3466          return new Intent(Intent.ACTION_VIEW)                                                                     
3467              .setData(new Uri.Builder()                                                                            
3468                  .scheme("market")                                                                                 
3469                  .authority("details")                                                                             
3470                  .appendQueryParameter("id", packageName)                                                          
3471                  .build());                                                                                        
3472      }                                                                                                             
3473                                                                                                                    
3474      /**                                                                                                           
3475 -     * This is called from the code that adds shortcuts from the intent receiver.  This                           
3476 -     * doesn't have a Cursor, but                                                                                 
3477 -     */                                                                                                           
3478 -    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    
3479 -            UserHandleCompat user, Context context) {                                                             
3480 -        return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);                        
3481 -    }                                                                                                             
3482 -                                                                                                                  
3483 -    /**                                                                                                           
3484       * Make an ShortcutInfo object for a shortcut that is an application.                                         
3485       *                                                                                                            
3486       * If c is not null, then it will be used to fill in missing data like the title and icon.                    
3487       */                                                                                                           
3488 -    public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    
3489 +    public ShortcutInfo getAppShortcutInfo(PackageManager manager, Intent intent,                                 
3490              UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,                      
3491 -            HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {                               
3492 +            boolean allowMissingTarget) {                                                                         
3493          if (user == null) {                                                                                       
3494              Log.d(TAG, "Null user found in getShortcutInfo");                                                     
3495              return null;                                                                                          
3496          }                                                                                                         
3497                                                                                                                    
3498          ComponentName componentName = intent.getComponent();                                                      
3499          if (componentName == null) {                                                                              
3500              Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                           
3501              return null;                                                                                          
3502          }                                                                                                         
3503                                                                                                                    
3504          Intent newIntent = new Intent(intent.getAction(), null);                                                  
3505          newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                          
3506          newIntent.setComponent(componentName);                                                                    
3507          LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                          
3508          if ((lai == null) && !allowMissingTarget) {                                                               
3509              Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                            
3510              return null;                                                                                          
3511          }                                                                                                         
3512                                                                                                                    
3513          final ShortcutInfo info = new ShortcutInfo();                                                             
3514 -                                                                                                                  
3515 -        // the resource -- This may implicitly give us back the fallback icon,                                    
3516 -        // but don't worry about that.  All we're doing with usingFallbackIcon is                                 
3517 -        // to avoid saving lots of copies of that in the database, and most apps                                  
3518 -        // have icons anyway.                                                                                     
3519 -        Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);                                         
3520 -                                                                                                                  
3521 -        // the db                                                                                                 
3522 -        if (icon == null) {                                                                                       
3523 -            if (c != null) {                                                                                      
3524 -                icon = getIconFromCursor(c, iconIndex, context);                                                  
3525 -            }                                                                                                     
3526 -        }                                                                                                         
3527 -        // the fallback icon                                                                                      
3528 -        if (icon == null) {                                                                                       
3529 -            icon = mIconCache.getDefaultIcon(user);                                                               
3530 -            info.usingFallbackIcon = true;                                                                        
3531 -        }                                                                                                         
3532 -        info.setIcon(icon);                                                                                       
3533 -                                                                                                                  
3534 -        // From the cache.                                                                                        
3535 -        if (labelCache != null) {                                                                                 
3536 -            info.title = labelCache.get(componentName);                                                           
3537 -        }                                                                                                         
3538 -                                                                                                                  
3539 -        // from the resource                                                                                      
3540 -        if (info.title == null && lai != null) {                                                                  
3541 -            info.title = lai.getLabel();                                                                          
3542 -            if (labelCache != null) {                                                                             
3543 -                labelCache.put(componentName, info.title);                                                        
3544 -            }                                                                                                     
3545 -        }                                                                                                         
3546 +        mIconCache.getTitleAndIcon(info, componentName, lai, user, false);                                        
3547 +        if (mIconCache.isDefaultIcon(info.getIcon(mIconCache), user) && c != null) {                              
3548 +            Bitmap icon = Utilities.createIconBitmap(c, iconIndex, context);                                      
3549 +            info.setIcon(icon == null ? mIconCache.getDefaultIcon(user) : icon);                                  
3550 +        }                                                                                                         
3551 +                                                                                                                  
3552          // from the db                                                                                            
3553 -        if (info.title == null) {                                                                                 
3554 -            if (c != null) {                                                                                      
3555 -                info.title =  c.getString(titleIndex);                                                            
3556 -            }                                                                                                     
3557 -        }                                                                                                         
3558 +        if (TextUtils.isEmpty(info.title) && c != null) {                                                         
3559 +            info.title =  c.getString(titleIndex);                                                                
3560 +        }                                                                                                         
3561 +                                                                                                                  
3562          // fall back to the class name of the activity                                                            
3563          if (info.title == null) {                                                                                 
3564              info.title = componentName.getClassName();                                                            
3565          }                                                                                                         
3566 +                                                                                                                  
3567          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                         
3568          info.user = user;                                                                                         
3569          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3570                  info.title.toString(), info.user);                                                                
3571          return info;                                                                                              
3572      }                                                                                                             
3573                                                                                                                    
3574      static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                                        
3575              ItemInfoFilter f) {                                                                                   
3576          HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                                     
3577          for (ItemInfo i : infos) {                                                                                
3578              if (i instanceof ShortcutInfo) {                                                                      
3579                  ShortcutInfo info = (ShortcutInfo) i;                                                             
3580                  ComponentName cn = info.getTargetComponent();                                                     
3581                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3582                      filtered.add(info);                                                                           
3583                  }                                                                                                 
3584              } else if (i instanceof FolderInfo) {                                                                 
3585                  FolderInfo info = (FolderInfo) i;                                                                 
3586                  for (ShortcutInfo s : info.contents) {                                                            
3587                      ComponentName cn = s.getTargetComponent();                                                    
3588                      if (cn != null && f.filterItem(info, s, cn)) {                                                
3589                          filtered.add(s);                                                                          
3590                      }                                                                                             
3591                  }                                                                                                 
3592              } else if (i instanceof LauncherAppWidgetInfo) {                                                      
3593                  LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                           
3594                  ComponentName cn = info.providerName;                                                             
3595                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3596                      filtered.add(info);                                                                           
3597                  }                                                                                                 
3598              }                                                                                                     
3599          }                                                                                                         
3600          return new ArrayList<ItemInfo>(filtered);                                                                 
3601      }                                                                                                             
3602                                                                                                                    
3603      private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                            
3604              final UserHandleCompat user) {                                                                        
3605          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
3606              @Override                                                                                             
3607              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
3608                  if (info.user == null) {                                                                          
3609                      return cn.equals(cname);                                                                      
3610                  } else {                                                                                          
3611                      return cn.equals(cname) && info.user.equals(user);                                            
3612                  }                                                                                                 
3613              }                                                                                                     
3614          };                                                                                                        
3615          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
3616      }                                                                                                             
3617                                                                                                                    
3618      /**                                                                                                           
3619       * Make an ShortcutInfo object for a shortcut that isn't an application.                                      
3620       */                                                                                                           
3621      private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                               
3622              int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,                        
3623              int titleIndex) {                                                                                     
3624                                                                                                                    
3625          Bitmap icon = null;                                                                                       
3626          final ShortcutInfo info = new ShortcutInfo();                                                             
3627          // Non-app shortcuts are only supported for current user.                                                 
3628          info.user = UserHandleCompat.myUserHandle();                                                              
3629          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3630                                                                                                                    
3631          // TODO: If there's an explicit component and we can't install that, delete it.                           
3632                                                                                                                    
3633          info.title = c.getString(titleIndex);                                                                     
3634                                                                                                                    
3635          int iconType = c.getInt(iconTypeIndex);                                                                   
3636          switch (iconType) {                                                                                       
3637          case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                                       
3638              String packageName = c.getString(iconPackageIndex);                                                   
3639              String resourceName = c.getString(iconResourceIndex);                                                 
3640              info.customIcon = false;                                                                              
3641              // the resource                                                                                       
3642              icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);                    
3643              // the db                                                                                             
3644              if (icon == null) {                                                                                   
3645 -                icon = getIconFromCursor(c, iconIndex, context);                                                  
3646 +                icon = Utilities.createIconBitmap(c, iconIndex, context);                                         
3647              }                                                                                                     
3648              // the fallback icon                                                                                  
3649              if (icon == null) {                                                                                   
3650                  icon = mIconCache.getDefaultIcon(info.user);                                                      
3651                  info.usingFallbackIcon = true;                                                                    
3652              }                                                                                                     
3653              break;                                                                                                
3654          case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                         
3655 -            icon = getIconFromCursor(c, iconIndex, context);                                                      
3656 +            icon = Utilities.createIconBitmap(c, iconIndex, context);                                             
3657              if (icon == null) {                                                                                   
3658                  icon = mIconCache.getDefaultIcon(info.user);                                                      
3659                  info.customIcon = false;                                                                          
3660                  info.usingFallbackIcon = true;                                                                    
3661              } else {                                                                                              
3662                  info.customIcon = true;                                                                           
3663              }                                                                                                     
3664              break;                                                                                                
3665          default:                                                                                                  
3666              icon = mIconCache.getDefaultIcon(info.user);                                                          
3667              info.usingFallbackIcon = true;                                                                        
3668              info.customIcon = false;                                                                              
3669              break;                                                                                                
3670          }                                                                                                         
3671          info.setIcon(icon);                                                                                       
3672          return info;                                                                                              
3673 -    }                                                                                                             
3674 -                                                                                                                  
3675 -    Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                          
3676 -        @SuppressWarnings("all") // suppress dead code warning                                                    
3677 -        final boolean debug = false;                                                                              
3678 -        if (debug) {                                                                                              
3679 -            Log.d(TAG, "getIconFromCursor app="                                                                   
3680 -                    + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));                    
3681 -        }                                                                                                         
3682 -        byte[] data = c.getBlob(iconIndex);                                                                       
3683 -        try {                                                                                                     
3684 -            return Utilities.createIconBitmap(                                                                    
3685 -                    BitmapFactory.decodeByteArray(data, 0, data.length), context);                                
3686 -        } catch (Exception e) {                                                                                   
3687 -            return null;                                                                                          
3688 -        }                                                                                                         
3689      }                                                                                                             
3690                                                                                                                    
3691      ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                           
3692          Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                                    
3693          String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                            
3694          Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                                  
3695                                                                                                                    
3696          if (intent == null) {                                                                                     
3697              // If the intent is null, we can't construct a valid ShortcutInfo, so we return null                  
3698              Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                           
3699              return null;                                                                                          
3700          }                                                                                                         
3701                                                                                                                    
3702          Bitmap icon = null;                                                                                       
3703          boolean customIcon = false;                                                                               
3704          ShortcutIconResource iconResource = null;                                                                 
3705                                                                                                                    
3706          if (bitmap instanceof Bitmap) {                                                                           
3707              icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                          
3708              customIcon = true;                                                                                    
3709          } else {                                                                                                  
3710              Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);                      
3711              if (extra instanceof ShortcutIconResource) {                                                          
3712                  iconResource = (ShortcutIconResource) extra;                                                      
3713                  icon = Utilities.createIconBitmap(iconResource.packageName,                                       
3714                          iconResource.resourceName, mIconCache, context);                                          
3715              }                                                                                                     
3716          }                                                                                                         
3717                                                                                                                    
3718          final ShortcutInfo info = new ShortcutInfo();                                                             
3719                                                                                                                    
3720          // Only support intents for current user for now. Intents sent from other                                 
3721          // users wouldn't get here without intent forwarding anyway.                                              
3722          info.user = UserHandleCompat.myUserHandle();                                                              
3723          if (icon == null) {                                                                                       
3724              icon = mIconCache.getDefaultIcon(info.user);                                                          
3725              info.usingFallbackIcon = true;                                                                        
3726          }                                                                                                         
3727          info.setIcon(icon);                                                                                       
3728                                                                                                                    
3729          info.title = name;                                                                                        
3730          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3731                  info.title.toString(), info.user);                                                                
3732          info.intent = intent;                                                                                     
3733          info.customIcon = customIcon;                                                                             
3734          info.iconResource = iconResource;                                                                         
3735                                                                                                                    
3736          return info;                                                                                              
3737 -    }                                                                                                             
3738 -                                                                                                                  
3739 -    boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,                      
3740 -            int iconIndex) {                                                                                      
3741 -        // If apps can't be on SD, don't even bother.                                                             
3742 -        if (!mAppsCanBeOnRemoveableStorage) {                                                                     
3743 -            return false;                                                                                         
3744 -        }                                                                                                         
3745 -        // If this icon doesn't have a custom icon, check to see                                                  
3746 -        // what's stored in the DB, and if it doesn't match what                                                  
3747 -        // we're going to show, store what we are going to show back                                              
3748 -        // into the DB.  We do this so when we're loading, if the                                                 
3749 -        // package manager can't find an icon (for example because                                                
3750 -        // the app is on SD) then we can use that instead.                                                        
3751 -        if (!info.customIcon && !info.usingFallbackIcon) {                                                        
3752 -            cache.put(info, c.getBlob(iconIndex));                                                                
3753 -            return true;                                                                                          
3754 -        }                                                                                                         
3755 -        return false;                                                                                             
3756 -    }                                                                                                             
3757 -    void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                                       
3758 -        boolean needSave = false;                                                                                 
3759 -        try {                                                                                                     
3760 -            if (data != null) {                                                                                   
3761 -                Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                               
3762 -                Bitmap loaded = info.getIcon(mIconCache);                                                         
3763 -                needSave = !saved.sameAs(loaded);                                                                 
3764 -            } else {                                                                                              
3765 -                needSave = true;                                                                                  
3766 -            }                                                                                                     
3767 -        } catch (Exception e) {                                                                                   
3768 -            needSave = true;                                                                                      
3769 -        }                                                                                                         
3770 -        if (needSave) {                                                                                           
3771 -            Log.d(TAG, "going to save icon bitmap for info=" + info);                                             
3772 -            // This is slower than is ideal, but this only happens once                                           
3773 -            // or when the app is updated with a new icon.                                                        
3774 -            updateItemInDatabase(context, info);                                                                  
3775 -        }                                                                                                         
3776      }                                                                                                             
3777                                                                                                                    
3778      /**                                                                                                           
3779       * Return an existing FolderInfo object if we have encountered this ID previously,                            
3780       * or make a new one.                                                                                         
3781       */                                                                                                           
3782      private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {                      
3783          // See if a placeholder was created for us already                                                        
3784          FolderInfo folderInfo = folders.get(id);                                                                  
3785          if (folderInfo == null) {                                                                                 
3786              // No placeholder -- create a new instance                                                            
3787              folderInfo = new FolderInfo();                                                                        
3788              folders.put(id, folderInfo);                                                                          
3789          }                                                                                                         
3790          return folderInfo;                                                                                        
3791      }                                                                                                             
3792                                                                                                                    
3793      public static final Comparator<AppInfo> getAppNameComparator() {                                              
3794          final Collator collator = Collator.getInstance();                                                         
3795          return new Comparator<AppInfo>() {                                                                        
3796              public final int compare(AppInfo a, AppInfo b) {                                                      
3797                  if (a.user.equals(b.user)) {                                                                      
3798                      int result = collator.compare(a.title.toString().trim(),                                      
3799                              b.title.toString().trim());                                                           
3800                      if (result == 0) {                                                                            
3801                          result = a.componentName.compareTo(b.componentName);                                      
3802                      }                                                                                             
3803                      return result;                                                                                
3804                  } else {                                                                                          
3805                      // TODO Need to figure out rules for sorting                                                  
3806                      // profiles, this puts work second.                                                           
3807                      return a.user.toString().compareTo(b.user.toString());                                        
3808                  }                                                                                                 
3809              }                                                                                                     
3810          };                                                                                                        
3811      }                                                                                                             
3812      public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                           
3813              = new Comparator<AppInfo>() {                                                                         
3814          public final int compare(AppInfo a, AppInfo b) {                                                          
3815              if (a.firstInstallTime < b.firstInstallTime) return 1;                                                
3816              if (a.firstInstallTime > b.firstInstallTime) return -1;                                               
3817              return 0;                                                                                             
3818          }                                                                                                         
3819      };                                                                                                            
3820      static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                                      
3821          if (info.activityInfo != null) {                                                                          
3822              return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);                      
3823          } else {                                                                                                  
3824              return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);                        
3825          }                                                                                                         
3826      }                                                                                                             
3827 -    public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {                
3828 -        private Collator mCollator;                                                                               
3829 -        private HashMap<Object, CharSequence> mLabelCache;                                                        
3830 -        ShortcutNameComparator(PackageManager pm) {                                                               
3831 -            mLabelCache = new HashMap<Object, CharSequence>();                                                    
3832 -            mCollator = Collator.getInstance();                                                                   
3833 -        }                                                                                                         
3834 -        ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {                                        
3835 -            mLabelCache = labelCache;                                                                             
3836 -            mCollator = Collator.getInstance();                                                                   
3837 -        }                                                                                                         
3838 -        public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {                    
3839 -            String labelA, labelB;                                                                                
3840 -            ComponentName keyA = a.getComponentName();                                                            
3841 -            ComponentName keyB = b.getComponentName();                                                            
3842 -            if (mLabelCache.containsKey(keyA)) {                                                                  
3843 -                labelA = mLabelCache.get(keyA).toString();                                                        
3844 -            } else {                                                                                              
3845 -                labelA = a.getLabel().toString().trim();                                                          
3846 -                                                                                                                  
3847 -                mLabelCache.put(keyA, labelA);                                                                    
3848 -            }                                                                                                     
3849 -            if (mLabelCache.containsKey(keyB)) {                                                                  
3850 -                labelB = mLabelCache.get(keyB).toString();                                                        
3851 -            } else {                                                                                              
3852 -                labelB = b.getLabel().toString().trim();                                                          
3853 -                                                                                                                  
3854 -                mLabelCache.put(keyB, labelB);                                                                    
3855 -            }                                                                                                     
3856 -            return mCollator.compare(labelA, labelB);                                                             
3857 -        }                                                                                                         
3858 -    };                                                                                                            
3859 +                                                                                                                  
3860      public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                           
3861          private final AppWidgetManagerCompat mManager;                                                            
3862          private final PackageManager mPackageManager;                                                             
3863          private final HashMap<Object, String> mLabelCache;                                                        
3864          private final Collator mCollator;                                                                         
3865                                                                                                                    
3866          WidgetAndShortcutNameComparator(Context context) {                                                        
3867              mManager = AppWidgetManagerCompat.getInstance(context);                                               
3868              mPackageManager = context.getPackageManager();                                                        
3869              mLabelCache = new HashMap<Object, String>();                                                          
3870              mCollator = Collator.getInstance();                                                                   
3871          }                                                                                                         
3872          public final int compare(Object a, Object b) {                                                            
3873              String labelA, labelB;                                                                                
3874              if (mLabelCache.containsKey(a)) {                                                                     
3875                  labelA = mLabelCache.get(a);                                                                      
3876              } else {                                                                                              
3877                  labelA = (a instanceof LauncherAppWidgetProviderInfo)                                             
3878                          ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a)                                   
3879                          : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                         
3880                  mLabelCache.put(a, labelA);                                                                       
3881              }                                                                                                     
3882              if (mLabelCache.containsKey(b)) {                                                                     
3883                  labelB = mLabelCache.get(b);                                                                      
3884              } else {                                                                                              
3885                  labelB = (b instanceof LauncherAppWidgetProviderInfo)                                             
3886                          ? mManager.loadLabel((LauncherAppWidgetProviderInfo) b)                                   
3887                          : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                         
3888                  mLabelCache.put(b, labelB);                                                                       
3889              }                                                                                                     
3890              return mCollator.compare(labelA, labelB);                                                             
3891          }                                                                                                         
3892      };                                                                                                            
3893                                                                                                                    
3894      static boolean isValidProvider(AppWidgetProviderInfo provider) {                                              
3895          return (provider != null) && (provider.provider != null)                                                  
3896                  && (provider.provider.getPackageName() != null);                                                  
3897      }                                                                                                             
3898                                                                                                                    
3899      public void dumpState() {                                                                                     
3900          Log.d(TAG, "mCallbacks=" + mCallbacks);                                                                   
3901          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                           
3902          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                         
3903          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);                     
3904          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);                   
3905          if (mLoaderTask != null) {                                                                                
3906              mLoaderTask.dumpState();                                                                              
3907          } else {                                                                                                  
3908              Log.d(TAG, "mLoaderTask=null");                                                                       
3909          }                                                                                                         
3910      }                                                                                                             
3911                                                                                                                    
3912      public Callbacks getCallback() {                                                                              
3913          return mCallbacks != null ? mCallbacks.get() : null;                                                      
3914      }                                                                                                             
3915  }                                                                                                                 
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.app.SearchManager;                                                                                 
  20  import android.appwidget.AppWidgetProviderInfo;                                                                   
  21  import android.content.BroadcastReceiver;                                                                         
  22  import android.content.ComponentName;                                                                             
  23  import android.content.ContentProviderClient;                                                                     
  24  import android.content.ContentProviderOperation;                                                                  
  25  import android.content.ContentResolver;                                                                           
  26  import android.content.ContentValues;                                                                             
  27  import android.content.Context;                                                                                   
  28  import android.content.Intent;                                                                                    
  29  import android.content.Intent.ShortcutIconResource;                                                               
  30  import android.content.IntentFilter;                                                                              
  31  import android.content.SharedPreferences;                                                                         
  32  import android.content.pm.PackageManager;                                                                         
  33  import android.content.pm.ProviderInfo;                                                                           
  34  import android.content.pm.ResolveInfo;                                                                            
  35  import android.content.res.Configuration;                                                                         
  36  import android.content.res.Resources;                                                                             
  37  import android.database.Cursor;                                                                                   
  38  import android.graphics.Bitmap;                                                                                   
  39  import android.graphics.BitmapFactory;                                                                            
  40  import android.graphics.Rect;                                                                                     
  41  import android.net.Uri;                                                                                           
  42  import android.os.Environment;                                                                                    
  43  import android.os.Handler;                                                                                        
  44  import android.os.HandlerThread;                                                                                  
  45  import android.os.Parcelable;                                                                                     
  46  import android.os.Process;                                                                                        
  47  import android.os.RemoteException;                                                                                
  48  import android.os.SystemClock;                                                                                    
  49  import android.provider.BaseColumns;                                                                              
  50  import android.text.TextUtils;                                                                                    
  51  import android.util.Log;                                                                                          
  52  import android.util.LongSparseArray;                                                                              
  53  import android.util.Pair;                                                                                         
  54                                                                                                                    
  55  import com.android.launcher3.compat.AppWidgetManagerCompat;                                                       
  56  import com.android.launcher3.compat.LauncherActivityInfoCompat;                                                   
  57  import com.android.launcher3.compat.LauncherAppsCompat;                                                           
  58  import com.android.launcher3.compat.PackageInstallerCompat;                                                       
  59  import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;                                    
  60  import com.android.launcher3.compat.UserHandleCompat;                                                             
  61  import com.android.launcher3.compat.UserManagerCompat;                                                            
  62                                                                                                                    
  63  import java.lang.ref.WeakReference;                                                                               
  64  import java.net.URISyntaxException;                                                                               
  65  import java.security.InvalidParameterException;                                                                   
  66  import java.text.Collator;                                                                                        
  67  import java.util.ArrayList;                                                                                       
  68  import java.util.Arrays;                                                                                          
  69  import java.util.Collection;                                                                                      
  70  import java.util.Collections;                                                                                     
  71  import java.util.Comparator;                                                                                      
  72  import java.util.HashMap;                                                                                         
  73  import java.util.HashSet;                                                                                         
  74  import java.util.Iterator;                                                                                        
  75  import java.util.List;                                                                                            
  76  import java.util.Map.Entry;                                                                                       
  77  import java.util.Set;                                                                                             
  78                                                                                                                    
  79  /**                                                                                                               
  80   * Maintains in-memory state of the Launcher. It is expected that there should be only one                        
  81   * LauncherModel object held in a static. Also provide APIs for updating the database state                       
  82   * for the Launcher.                                                                                              
  83   */                                                                                                               
  84  public class LauncherModel extends BroadcastReceiver                                                              
  85          implements LauncherAppsCompat.OnAppsChangedCallbackCompat {                                               
  86      static final boolean DEBUG_LOADERS = false;                                                                   
  87      private static final boolean DEBUG_RECEIVER = false;                                                          
  88      private static final boolean REMOVE_UNRESTORED_ICONS = true;                                                  
  89      private static final boolean ADD_MANAGED_PROFILE_SHORTCUTS = false;                                           
  90                                                                                                                    
  91      static final String TAG = "Launcher.Model";                                                                   
  92                                                                                                                    
  93      public static final int LOADER_FLAG_NONE = 0;                                                                 
  94      public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                                 
  95      public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                               
  96                                                                                                                    
  97      private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                               
  98      private static final long INVALID_SCREEN_ID = -1L;                                                            
  99                                                                                                                    
 100      private final boolean mAppsCanBeOnRemoveableStorage;                                                          
 101      private final boolean mOldContentProviderExists;                                                              
 102                                                                                                                    
 103      private final LauncherAppState mApp;                                                                          
 104      private final Object mLock = new Object();                                                                    
 105      private DeferredHandler mHandler = new DeferredHandler();                                                     
 106      private LoaderTask mLoaderTask;                                                                               
 107      private boolean mIsLoaderTaskRunning;                                                                         
 108                                                                                                                    
 109      /**                                                                                                           
 110       * Maintain a set of packages per user, for which we added a shortcut on the workspace.                       
 111       */                                                                                                           
 112      private static final String INSTALLED_SHORTCUTS_SET_PREFIX = "installed_shortcuts_set_for_user_";             
 113                                                                                                                    
 114      // Specific runnable types that are run on the main thread deferred handler, this allows us to                
 115      // clear all queued binding runnables when the Launcher activity is destroyed.                                
 116      private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                                     
 117      private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                                    
 118                                                                                                                    
 119      private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";                             
 120                                                                                                                    
 121      private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                      
 122      static {                                                                                                      
 123          sWorkerThread.start();                                                                                    
 124      }                                                                                                             
 125      private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                
 126                                                                                                                    
 127      // We start off with everything not loaded.  After that, we assume that                                       
 128      // our monitoring of the package manager provides all updates and we never                                    
 129      // need to do a requery.  These are only ever touched from the loader thread.                                 
 130      private boolean mWorkspaceLoaded;                                                                             
 131      private boolean mAllAppsLoaded;                                                                               
 132                                                                                                                    
 133      // When we are loading pages synchronously, we can't just post the binding of items on the side               
 134      // pages as this delays the rotation process.  Instead, we wait for a callback from the first                 
 135      // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start                
 136      // a normal load, we also clear this set of Runnables.                                                        
 137      static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                          
 138                                                                                                                    
 139      private WeakReference<Callbacks> mCallbacks;                                                                  
 140                                                                                                                    
 141      // < only access in worker thread >                                                                           
 142      AllAppsList mBgAllAppsList;                                                                                   
 143                                                                                                                    
 144      // The lock that must be acquired before referencing any static bg data structures.  Unlike                   
 145      // other locks, this one can generally be held long-term because we never expect any of these                 
 146      // static data structures to be referenced outside of the worker thread except on the first                   
 147      // load after configuration change.                                                                           
 148      static final Object sBgLock = new Object();                                                                   
 149                                                                                                                    
 150      // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by                        
 151      // LauncherModel to their ids                                                                                 
 152      static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                           
 153                                                                                                                    
 154      // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts                
 155      //       created by LauncherModel that are directly on the home screen (however, no widgets or                
 156      //       shortcuts within folders).                                                                           
 157      static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                               
 158                                                                                                                    
 159      // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()             
 160      static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                                 
 161          new ArrayList<LauncherAppWidgetInfo>();                                                                   
 162                                                                                                                    
 163      // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                            
 164      static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                          
 165                                                                                                                    
 166      // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database               
 167      static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                          
 168                                                                                                                    
 169      // sBgWorkspaceScreens is the ordered set of workspace screens.                                               
 170      static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                                     
 171                                                                                                                    
 172      // sBgWidgetProviders is the set of widget providers including custom internal widgets                        
 173      public static HashMap<ComponentName, LauncherAppWidgetProviderInfo> sBgWidgetProviders;                       
 174      public static boolean sWidgetProvidersDirty;                                                                  
 175                                                                                                                    
 176      // sPendingPackages is a set of packages which could be on sdcard and are not available yet                   
 177      static final HashMap<UserHandleCompat, HashSet<String>> sPendingPackages =                                    
 178              new HashMap<UserHandleCompat, HashSet<String>>();                                                     
 179                                                                                                                    
 180      // </ only access in worker thread >                                                                          
 181                                                                                                                    
 182      private IconCache mIconCache;                                                                                 
 183                                                                                                                    
 184      protected int mPreviousConfigMcc;                                                                             
 185                                                                                                                    
 186      private final LauncherAppsCompat mLauncherApps;                                                               
 187      private final UserManagerCompat mUserManager;                                                                 
 188                                                                                                                    
 189      public interface Callbacks {                                                                                  
 190          public boolean setLoadOnResume();                                                                         
 191          public int getCurrentWorkspaceScreen();                                                                   
 192          public void startBinding();                                                                               
 193          public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                                  
 194                                boolean forceAnimateIcons);                                                         
 195          public void bindScreens(ArrayList<Long> orderedScreenIds);                                                
 196          public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                             
 197          public void bindFolders(HashMap<Long,FolderInfo> folders);                                                
 198          public void finishBindingItems();                                                                         
 199          public void bindAppWidget(LauncherAppWidgetInfo info);                                                    
 200          public void bindAllApplications(ArrayList<AppInfo> apps);                                                 
 201          public void bindAppsAdded(ArrayList<Long> newScreens,                                                     
 202                                    ArrayList<ItemInfo> addNotAnimated,                                             
 203                                    ArrayList<ItemInfo> addAnimated,                                                
 204                                    ArrayList<AppInfo> addedApps);                                                  
 205          public void bindAppsUpdated(ArrayList<AppInfo> apps);                                                     
 206          public void bindShortcutsChanged(ArrayList<ShortcutInfo> updated,                                         
 207                  ArrayList<ShortcutInfo> removed, UserHandleCompat user);                                          
 208          public void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);                                
 209          public void updatePackageState(ArrayList<PackageInstallInfo> installInfo);                                
 210          public void updatePackageBadge(String packageName);                                                       
 211          public void bindComponentsRemoved(ArrayList<String> packageNames,                                         
 212                          ArrayList<AppInfo> appInfos, UserHandleCompat user, int reason);                          
 213          public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                                   
 214          public void bindSearchablesChanged();                                                                     
 215          public boolean isAllAppsButtonRank(int rank);                                                             
 216          public void onPageBoundSynchronously(int page);                                                           
 217          public void dumpLogsToLocalData();                                                                        
 218          public void bindAddPendingItem(PendingAddItemInfo info, long container, long screenId,                    
 219                  int[] cell, int spanX, int spanY);                                                                
 220      }                                                                                                             
 221                                                                                                                    
 222      public interface ItemInfoFilter {                                                                             
 223          public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                              
 224      }                                                                                                             
 225                                                                                                                    
 226      public interface ScreenPosProvider {                                                                          
 227          int getScreenIndex(ArrayList<Long> screenIDs);                                                            
 228      }                                                                                                             
 229                                                                                                                    
 230      LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                               
 231          Context context = app.getContext();                                                                       
 232                                                                                                                    
 233          mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                                 
 234          String oldProvider = context.getString(R.string.old_launcher_provider_uri);                               
 235          // This may be the same as MIGRATE_AUTHORITY, or it may be replaced by a different                        
 236          // resource string.                                                                                       
 237          String redirectAuthority = Uri.parse(oldProvider).getAuthority();                                         
 238          ProviderInfo providerInfo =                                                                               
 239                  context.getPackageManager().resolveContentProvider(MIGRATE_AUTHORITY, 0);                         
 240          ProviderInfo redirectProvider =                                                                           
 241                  context.getPackageManager().resolveContentProvider(redirectAuthority, 0);                         
 242                                                                                                                    
 243          Log.d(TAG, "Old launcher provider: " + oldProvider);                                                      
 244          mOldContentProviderExists = (providerInfo != null) && (redirectProvider != null);                         
 245                                                                                                                    
 246          if (mOldContentProviderExists) {                                                                          
 247              Log.d(TAG, "Old launcher provider exists.");                                                          
 248          } else {                                                                                                  
 249              Log.d(TAG, "Old launcher provider does not exist.");                                                  
 250          }                                                                                                         
 251                                                                                                                    
 252          mApp = app;                                                                                               
 253          mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                                   
 254          mIconCache = iconCache;                                                                                   
 255                                                                                                                    
 256          final Resources res = context.getResources();                                                             
 257          Configuration config = res.getConfiguration();                                                            
 258          mPreviousConfigMcc = config.mcc;                                                                          
 259          mLauncherApps = LauncherAppsCompat.getInstance(context);                                                  
 260          mUserManager = UserManagerCompat.getInstance(context);                                                    
 261      }                                                                                                             
 262                                                                                                                    
 263      /** Runs the specified runnable immediately if called from the main thread, otherwise it is                   
 264       * posted on the main thread handler. */                                                                      
 265      private void runOnMainThread(Runnable r) {                                                                    
 266          runOnMainThread(r, 0);                                                                                    
 267      }                                                                                                             
 268      private void runOnMainThread(Runnable r, int type) {                                                          
 269          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 270              // If we are on the worker thread, post onto the main handler                                         
 271              mHandler.post(r);                                                                                     
 272          } else {                                                                                                  
 273              r.run();                                                                                              
 274          }                                                                                                         
 275      }                                                                                                             
 276                                                                                                                    
 277      /** Runs the specified runnable immediately if called from the worker thread, otherwise it is                 
 278       * posted on the worker thread handler. */                                                                    
 279      private static void runOnWorkerThread(Runnable r) {                                                           
 280          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 281              r.run();                                                                                              
 282          } else {                                                                                                  
 283              // If we are not on the worker thread, then post to the worker handler                                
 284              sWorker.post(r);                                                                                      
 285          }                                                                                                         
 286      }                                                                                                             
 287                                                                                                                    
 288      boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                                      
 289          return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                                  
 290      }                                                                                                             
 291                                                                                                                    
 292      public void setPackageState(final ArrayList<PackageInstallInfo> installInfo) {                                
 293          // Process the updated package state                                                                      
 294          Runnable r = new Runnable() {                                                                             
 295              public void run() {                                                                                   
 296                  Callbacks callbacks = getCallback();                                                              
 297                  if (callbacks != null) {                                                                          
 298                      callbacks.updatePackageState(installInfo);                                                    
 299                  }                                                                                                 
 300              }                                                                                                     
 301          };                                                                                                        
 302          mHandler.post(r);                                                                                         
 303      }                                                                                                             
 304                                                                                                                    
 305      public void updatePackageBadge(final String packageName) {                                                    
 306          // Process the updated package badge                                                                      
 307          Runnable r = new Runnable() {                                                                             
 308              public void run() {                                                                                   
 309                  Callbacks callbacks = getCallback();                                                              
 310                  if (callbacks != null) {                                                                          
 311                      callbacks.updatePackageBadge(packageName);                                                    
 312                  }                                                                                                 
 313              }                                                                                                     
 314          };                                                                                                        
 315          mHandler.post(r);                                                                                         
 316      }                                                                                                             
 317                                                                                                                    
 318      public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                       
 319          final Callbacks callbacks = getCallback();                                                                
 320                                                                                                                    
 321          if (allAppsApps == null) {                                                                                
 322              throw new RuntimeException("allAppsApps must not be null");                                           
 323          }                                                                                                         
 324          if (allAppsApps.isEmpty()) {                                                                              
 325              return;                                                                                               
 326          }                                                                                                         
 327                                                                                                                    
 328          // Process the newly added applications and add them to the database first                                
 329          Runnable r = new Runnable() {                                                                             
 330              public void run() {                                                                                   
 331                  runOnMainThread(new Runnable() {                                                                  
 332                      public void run() {                                                                           
 333                          Callbacks cb = getCallback();                                                             
 334                          if (callbacks == cb && cb != null) {                                                      
 335                              callbacks.bindAppsAdded(null, null, null, allAppsApps);                               
 336                          }                                                                                         
 337                      }                                                                                             
 338                  });                                                                                               
 339              }                                                                                                     
 340          };                                                                                                        
 341          runOnWorkerThread(r);                                                                                     
 342      }                                                                                                             
 343                                                                                                                    
 344      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 345              final ArrayList<ItemInfo> workspaceApps) {                                                            
 346          addAndBindAddedWorkspaceApps(context, workspaceApps,                                                      
 347                  new ScreenPosProvider() {                                                                         
 348                                                                                                                    
 349                      @Override                                                                                     
 350                      public int getScreenIndex(ArrayList<Long> screenIDs) {                                        
 351                          return screenIDs.isEmpty() ? 0 : 1;                                                       
 352                      }                                                                                             
 353                  }, 1, false);                                                                                     
 354      }                                                                                                             
 355                                                                                                                    
 356      private static boolean findNextAvailableIconSpaceInScreen(ArrayList<Rect> occupiedPos,                        
 357              int[] xy, int spanX, int spanY) {                                                                     
 358          LauncherAppState app = LauncherAppState.getInstance();                                                    
 359          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 360          final int xCount = (int) grid.numColumns;                                                                 
 361          final int yCount = (int) grid.numRows;                                                                    
 362          boolean[][] occupied = new boolean[xCount][yCount];                                                       
 363          if (occupiedPos != null) {                                                                                
 364              for (Rect r : occupiedPos) {                                                                          
 365                  for (int x = r.left; 0 <= x && x < r.right && x < xCount; x++) {                                  
 366                      for (int y = r.top; 0 <= y && y < r.bottom && y < yCount; y++) {                              
 367                          occupied[x][y] = true;                                                                    
 368                      }                                                                                             
 369                  }                                                                                                 
 370              }                                                                                                     
 371          }                                                                                                         
 372          return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);                             
 373      }                                                                                                             
 374                                                                                                                    
 375      /**                                                                                                           
 376       * Find a position on the screen for the given size or adds a new screen.                                     
 377       * @return screenId and the coordinates for the item.                                                         
 378       */                                                                                                           
 379      private static Pair<Long, int[]> findSpaceForItem(                                                            
 380              Context context,                                                                                      
 381              ScreenPosProvider preferredScreen,                                                                    
 382              int fallbackStartScreen,                                                                              
 383              ArrayList<Long> workspaceScreens,                                                                     
 384              ArrayList<Long> addedWorkspaceScreensFinal,                                                           
 385              int spanX, int spanY) {                                                                               
 386          // Load position of items which are on the desktop. We can't use sBgItemsIdMap because                    
 387          // loadWorkspace() may not have been called.                                                              
 388          final ContentResolver cr = context.getContentResolver();                                                  
 389          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 390                  new String[] {                                                                                    
 391                      LauncherSettings.Favorites.SCREEN,                                                            
 392                      LauncherSettings.Favorites.CELLX,                                                             
 393                      LauncherSettings.Favorites.CELLY,                                                             
 394                      LauncherSettings.Favorites.SPANX,                                                             
 395                      LauncherSettings.Favorites.SPANY,                                                             
 396                      LauncherSettings.Favorites.CONTAINER                                                          
 397                   },                                                                                               
 398                   "container=?",                                                                                   
 399                   new String[] { Integer.toString(LauncherSettings.Favorites.CONTAINER_DESKTOP) },                 
 400                   null);                                                                                           
 401                                                                                                                    
 402          final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);                       
 403          final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                         
 404          final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                         
 405          final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                         
 406          final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                         
 407          LongSparseArray<ArrayList<Rect>> screenItems = new LongSparseArray<ArrayList<Rect>>();                    
 408          try {                                                                                                     
 409              while (c.moveToNext()) {                                                                              
 410                  Rect rect = new Rect();                                                                           
 411                  rect.left = c.getInt(cellXIndex);                                                                 
 412                  rect.top = c.getInt(cellYIndex);                                                                  
 413                  rect.right = rect.left + Math.max(1, c.getInt(spanXIndex));                                       
 414                  rect.bottom = rect.top + Math.max(1, c.getInt(spanYIndex));                                       
 415                                                                                                                    
 416                  long screenId = c.getInt(screenIndex);                                                            
 417                  ArrayList<Rect> items = screenItems.get(screenId);                                                
 418                  if (items == null) {                                                                              
 419                      items = new ArrayList<Rect>();                                                                
 420                      screenItems.put(screenId, items);                                                             
 421                  }                                                                                                 
 422                  items.add(rect);                                                                                  
 423              }                                                                                                     
 424          } catch (Exception e) {                                                                                   
 425              screenItems.clear();                                                                                  
 426          } finally {                                                                                               
 427              c.close();                                                                                            
 428          }                                                                                                         
 429                                                                                                                    
 430          // Find appropriate space for the item.                                                                   
 431          long screenId = 0;                                                                                        
 432          int[] cordinates = new int[2];                                                                            
 433          boolean found = false;                                                                                    
 434                                                                                                                    
 435          int screenCount = workspaceScreens.size();                                                                
 436          // First check the preferred screen.                                                                      
 437          int preferredScreenIndex = preferredScreen.getScreenIndex(workspaceScreens);                              
 438          if (preferredScreenIndex < screenCount) {                                                                 
 439              screenId = workspaceScreens.get(preferredScreenIndex);                                                
 440              found = findNextAvailableIconSpaceInScreen(                                                           
 441                      screenItems.get(screenId), cordinates, spanX, spanY);                                         
 442          }                                                                                                         
 443                                                                                                                    
 444          if (!found) {                                                                                             
 445              // Search on any of the screens.                                                                      
 446              for (int screen = fallbackStartScreen; screen < screenCount; screen++) {                              
 447                  screenId = workspaceScreens.get(screen);                                                          
 448                  if (findNextAvailableIconSpaceInScreen(                                                           
 449                          screenItems.get(screenId), cordinates, spanX, spanY)) {                                   
 450                      // We found a space for it                                                                    
 451                      found = true;                                                                                 
 452                      break;                                                                                        
 453                  }                                                                                                 
 454              }                                                                                                     
 455          }                                                                                                         
 456                                                                                                                    
 457          if (!found) {                                                                                             
 458              // Still no position found. Add a new screen to the end.                                              
 459              screenId = LauncherAppState.getLauncherProvider().generateNewScreenId();                              
 460                                                                                                                    
 461              // Save the screen id for binding in the workspace                                                    
 462              workspaceScreens.add(screenId);                                                                       
 463              addedWorkspaceScreensFinal.add(screenId);                                                             
 464                                                                                                                    
 465              // If we still can't find an empty space, then God help us all!!!                                     
 466              if (!findNextAvailableIconSpaceInScreen(                                                              
 467                      screenItems.get(screenId), cordinates, spanX, spanY)) {                                       
 468                  throw new RuntimeException("Can't find space to add the item");                                   
 469              }                                                                                                     
 470          }                                                                                                         
 471          return Pair.create(screenId, cordinates);                                                                 
 472      }                                                                                                             
 473                                                                                                                    
 474      /**                                                                                                           
 475       * Adds the provided items to the workspace.                                                                  
 476       * @param preferredScreen the screen where we should try to add the app first                                 
 477       * @param fallbackStartScreen the screen to start search for empty space if                                   
 478       * preferredScreen is not available.                                                                          
 479       */                                                                                                           
 480      public void addAndBindPendingItem(                                                                            
 481              final Context context,                                                                                
 482              final PendingAddItemInfo addInfo,                                                                     
 483              final ScreenPosProvider preferredScreen,                                                              
 484              final int fallbackStartScreen) {                                                                      
 485          final Callbacks callbacks = getCallback();                                                                
 486          // Process the newly added applications and add them to the database first                                
 487          Runnable r = new Runnable() {                                                                             
 488              public void run() {                                                                                   
 489                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 490                  ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                               
 491                                                                                                                    
 492                  // Find appropriate space for the item.                                                           
 493                  Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                             
 494                          fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                        
 495                          addInfo.spanX,                                                                            
 496                          addInfo.spanY);                                                                           
 497                  final long screenId = coords.first;                                                               
 498                  final int[] cordinates = coords.second;                                                           
 499                                                                                                                    
 500                  // Update the workspace screens                                                                   
 501                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 502                  runOnMainThread(new Runnable() {                                                                  
 503                      public void run() {                                                                           
 504                          Callbacks cb = getCallback();                                                             
 505                          if (callbacks == cb && cb != null) {                                                      
 506                              cb.bindAddScreens(addedWorkspaceScreensFinal);                                        
 507                              cb.bindAddPendingItem(addInfo,                                                        
 508                                      LauncherSettings.Favorites.CONTAINER_DESKTOP,                                 
 509                                      screenId, cordinates, addInfo.spanX, addInfo.spanY);                          
 510                          }                                                                                         
 511                      }                                                                                             
 512                  });                                                                                               
 513              }                                                                                                     
 514          };                                                                                                        
 515          runOnWorkerThread(r);                                                                                     
 516      }                                                                                                             
 517                                                                                                                    
 518      /**                                                                                                           
 519       * Adds the provided items to the workspace.                                                                  
 520       * @param preferredScreen the screen where we should try to add the app first                                 
 521       * @param fallbackStartScreen the screen to start search for empty space if                                   
 522       * preferredScreen is not available.                                                                          
 523       */                                                                                                           
 524      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 525              final ArrayList<ItemInfo> workspaceApps,                                                              
 526              final ScreenPosProvider preferredScreen,                                                              
 527              final int fallbackStartScreen,                                                                        
 528              final boolean allowDuplicate) {                                                                       
 529          final Callbacks callbacks = getCallback();                                                                
 530          if (workspaceApps.isEmpty()) {                                                                            
 531              return;                                                                                               
 532          }                                                                                                         
 533          // Process the newly added applications and add them to the database first                                
 534          Runnable r = new Runnable() {                                                                             
 535              public void run() {                                                                                   
 536                  final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();                        
 537                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 538                                                                                                                    
 539                  // Get the list of workspace screens.  We need to append to this list and                         
 540                  // can not use sBgWorkspaceScreens because loadWorkspace() may not have been                      
 541                  // called.                                                                                        
 542                  ArrayList<Long> workspaceScreens = loadWorkspaceScreensDb(context);                               
 543                  synchronized(sBgLock) {                                                                           
 544                      for (ItemInfo item : workspaceApps) {                                                         
 545                          if (!allowDuplicate) {                                                                    
 546                              // Short-circuit this logic if the icon exists somewhere on the workspace             
 547                              if (shortcutExists(context, item.title.toString(),                                    
 548                                      item.getIntent(), item.user)) {                                               
 549                                  continue;                                                                         
 550                              }                                                                                     
 551                          }                                                                                         
 552                                                                                                                    
 553                          // Find appropriate space for the item.                                                   
 554                          Pair<Long, int[]> coords = findSpaceForItem(context, preferredScreen,                     
 555                                  fallbackStartScreen, workspaceScreens, addedWorkspaceScreensFinal,                
 556                                  1, 1);                                                                            
 557                          long screenId = coords.first;                                                             
 558                          int[] cordinates = coords.second;                                                         
 559                                                                                                                    
 560                          ShortcutInfo shortcutInfo;                                                                
 561                          if (item instanceof ShortcutInfo) {                                                       
 562                              shortcutInfo = (ShortcutInfo) item;                                                   
 563                          } else if (item instanceof AppInfo) {                                                     
 564                              shortcutInfo = ((AppInfo) item).makeShortcut();                                       
 565                          } else {                                                                                  
 566                              throw new RuntimeException("Unexpected info type");                                   
 567                          }                                                                                         
 568                                                                                                                    
 569                          // Add the shortcut to the db                                                             
 570                          addItemToDatabase(context, shortcutInfo,                                                  
 571                                  LauncherSettings.Favorites.CONTAINER_DESKTOP,                                     
 572                                  screenId, cordinates[0], cordinates[1], false);                                   
 573                          // Save the ShortcutInfo for binding in the workspace                                     
 574                          addedShortcutsFinal.add(shortcutInfo);                                                    
 575                      }                                                                                             
 576                  }                                                                                                 
 577                                                                                                                    
 578                  // Update the workspace screens                                                                   
 579                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 580                                                                                                                    
 581                  if (!addedShortcutsFinal.isEmpty()) {                                                             
 582                      runOnMainThread(new Runnable() {                                                              
 583                          public void run() {                                                                       
 584                              Callbacks cb = getCallback();                                                         
 585                              if (callbacks == cb && cb != null) {                                                  
 586                                  final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();                
 587                                  final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();             
 588                                  if (!addedShortcutsFinal.isEmpty()) {                                             
 589                                      ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);      
 590                                      long lastScreenId = info.screenId;                                            
 591                                      for (ItemInfo i : addedShortcutsFinal) {                                      
 592                                          if (i.screenId == lastScreenId) {                                         
 593                                              addAnimated.add(i);                                                   
 594                                          } else {                                                                  
 595                                              addNotAnimated.add(i);                                                
 596                                          }                                                                         
 597                                      }                                                                             
 598                                  }                                                                                 
 599                                  callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                               
 600                                          addNotAnimated, addAnimated, null);                                       
 601                              }                                                                                     
 602                          }                                                                                         
 603                      });                                                                                           
 604                  }                                                                                                 
 605              }                                                                                                     
 606          };                                                                                                        
 607          runOnWorkerThread(r);                                                                                     
 608      }                                                                                                             
 609                                                                                                                    
 610      public void unbindItemInfosAndClearQueuedBindRunnables() {                                                    
 611          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 612              throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +              
 613                      "main thread");                                                                               
 614          }                                                                                                         
 615                                                                                                                    
 616          // Clear any deferred bind runnables                                                                      
 617          synchronized (mDeferredBindRunnables) {                                                                   
 618              mDeferredBindRunnables.clear();                                                                       
 619          }                                                                                                         
 620          // Remove any queued bind runnables                                                                       
 621          mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                          
 622          // Unbind all the workspace items                                                                         
 623          unbindWorkspaceItemsOnMainThread();                                                                       
 624      }                                                                                                             
 625                                                                                                                    
 626      /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                                 
 627      void unbindWorkspaceItemsOnMainThread() {                                                                     
 628          // Ensure that we don't use the same workspace items data structure on the main thread                    
 629          // by making a copy of workspace items first.                                                             
 630          final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                                  
 631          final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                                      
 632          synchronized (sBgLock) {                                                                                  
 633              tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                          
 634              tmpAppWidgets.addAll(sBgAppWidgets);                                                                  
 635          }                                                                                                         
 636          Runnable r = new Runnable() {                                                                             
 637                  @Override                                                                                         
 638                  public void run() {                                                                               
 639                     for (ItemInfo item : tmpWorkspaceItems) {                                                      
 640                         item.unbind();                                                                             
 641                     }                                                                                              
 642                     for (ItemInfo item : tmpAppWidgets) {                                                          
 643                         item.unbind();                                                                             
 644                     }                                                                                              
 645                  }                                                                                                 
 646              };                                                                                                    
 647          runOnMainThread(r);                                                                                       
 648      }                                                                                                             
 649                                                                                                                    
 650      /**                                                                                                           
 651       * Adds an item to the DB if it was not created previously, or move it to a new                               
 652       * <container, screen, cellX, cellY>                                                                          
 653       */                                                                                                           
 654      static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                           
 655              long screenId, int cellX, int cellY) {                                                                
 656          if (item.container == ItemInfo.NO_ID) {                                                                   
 657              // From all apps                                                                                      
 658              addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                           
 659          } else {                                                                                                  
 660              // From somewhere else                                                                                
 661              moveItemInDatabase(context, item, container, screenId, cellX, cellY);                                 
 662          }                                                                                                         
 663      }                                                                                                             
 664                                                                                                                    
 665      static void checkItemInfoLocked(                                                                              
 666              final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                             
 667          ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                           
 668          if (modelItem != null && item != modelItem) {                                                             
 669              // check all the data is consistent                                                                   
 670              if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                              
 671                  ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                            
 672                  ShortcutInfo shortcut = (ShortcutInfo) item;                                                      
 673                  if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                           
 674                          modelShortcut.intent.filterEquals(shortcut.intent) &&                                     
 675                          modelShortcut.id == shortcut.id &&                                                        
 676                          modelShortcut.itemType == shortcut.itemType &&                                            
 677                          modelShortcut.container == shortcut.container &&                                          
 678                          modelShortcut.screenId == shortcut.screenId &&                                            
 679                          modelShortcut.cellX == shortcut.cellX &&                                                  
 680                          modelShortcut.cellY == shortcut.cellY &&                                                  
 681                          modelShortcut.spanX == shortcut.spanX &&                                                  
 682                          modelShortcut.spanY == shortcut.spanY &&                                                  
 683                          ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                           
 684                          (modelShortcut.dropPos != null &&                                                         
 685                                  shortcut.dropPos != null &&                                                       
 686                                  modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                                
 687                          modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                                      
 688                      // For all intents and purposes, this is the same object                                      
 689                      return;                                                                                       
 690                  }                                                                                                 
 691              }                                                                                                     
 692                                                                                                                    
 693              // the modelItem needs to match up perfectly with item if our model is                                
 694              // to be consistent with the database-- for now, just require                                         
 695              // modelItem == item or the equality check above                                                      
 696              String msg = "item: " + ((item != null) ? item.toString() : "null") +                                 
 697                      "modelItem: " +                                                                               
 698                      ((modelItem != null) ? modelItem.toString() : "null") +                                       
 699                      "Error: ItemInfo passed to checkItemInfo doesn't match original";                             
 700              RuntimeException e = new RuntimeException(msg);                                                       
 701              if (stackTrace != null) {                                                                             
 702                  e.setStackTrace(stackTrace);                                                                      
 703              }                                                                                                     
 704              throw e;                                                                                              
 705          }                                                                                                         
 706      }                                                                                                             
 707                                                                                                                    
 708      static void checkItemInfo(final ItemInfo item) {                                                              
 709          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 710          final long itemId = item.id;                                                                              
 711          Runnable r = new Runnable() {                                                                             
 712              public void run() {                                                                                   
 713                  synchronized (sBgLock) {                                                                          
 714                      checkItemInfoLocked(itemId, item, stackTrace);                                                
 715                  }                                                                                                 
 716              }                                                                                                     
 717          };                                                                                                        
 718          runOnWorkerThread(r);                                                                                     
 719      }                                                                                                             
 720                                                                                                                    
 721      static void updateItemInDatabaseHelper(Context context, final ContentValues values,                           
 722              final ItemInfo item, final String callingFunction) {                                                  
 723          final long itemId = item.id;                                                                              
 724          final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                                  
 725          final ContentResolver cr = context.getContentResolver();                                                  
 726                                                                                                                    
 727          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 728          Runnable r = new Runnable() {                                                                             
 729              public void run() {                                                                                   
 730                  cr.update(uri, values, null, null);                                                               
 731                  updateItemArrays(item, itemId, stackTrace);                                                       
 732              }                                                                                                     
 733          };                                                                                                        
 734          runOnWorkerThread(r);                                                                                     
 735      }                                                                                                             
 736                                                                                                                    
 737      static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,           
 738              final ArrayList<ItemInfo> items, final String callingFunction) {                                      
 739          final ContentResolver cr = context.getContentResolver();                                                  
 740                                                                                                                    
 741          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 742          Runnable r = new Runnable() {                                                                             
 743              public void run() {                                                                                   
 744                  ArrayList<ContentProviderOperation> ops =                                                         
 745                          new ArrayList<ContentProviderOperation>();                                                
 746                  int count = items.size();                                                                         
 747                  for (int i = 0; i < count; i++) {                                                                 
 748                      ItemInfo item = items.get(i);                                                                 
 749                      final long itemId = item.id;                                                                  
 750                      final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                      
 751                      ContentValues values = valuesList.get(i);                                                     
 752                                                                                                                    
 753                      ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());                  
 754                      updateItemArrays(item, itemId, stackTrace);                                                   
 755                                                                                                                    
 756                  }                                                                                                 
 757                  try {                                                                                             
 758                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
 759                  } catch (Exception e) {                                                                           
 760                      e.printStackTrace();                                                                          
 761                  }                                                                                                 
 762              }                                                                                                     
 763          };                                                                                                        
 764          runOnWorkerThread(r);                                                                                     
 765      }                                                                                                             
 766                                                                                                                    
 767      static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {                    
 768          // Lock on mBgLock *after* the db operation                                                               
 769          synchronized (sBgLock) {                                                                                  
 770              checkItemInfoLocked(itemId, item, stackTrace);                                                        
 771                                                                                                                    
 772              if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
 773                      item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 774                  // Item is in a folder, make sure this folder exists                                              
 775                  if (!sBgFolders.containsKey(item.container)) {                                                    
 776                      // An items container is being set to a that of an item which is not in                       
 777                      // the list of Folders.                                                                       
 778                      String msg = "item: " + item + " container being set to: " +                                  
 779                              item.container + ", not in the list of folders";                                      
 780                      Log.e(TAG, msg);                                                                              
 781                  }                                                                                                 
 782              }                                                                                                     
 783                                                                                                                    
 784              // Items are added/removed from the corresponding FolderInfo elsewhere, such                          
 785              // as in Workspace.onDrop. Here, we just add/remove them from the list of items                       
 786              // that are on the desktop, as appropriate                                                            
 787              ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                       
 788              if (modelItem != null &&                                                                              
 789                      (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                       
 790                       modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {                      
 791                  switch (modelItem.itemType) {                                                                     
 792                      case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                        
 793                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
 794                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 795                          if (!sBgWorkspaceItems.contains(modelItem)) {                                             
 796                              sBgWorkspaceItems.add(modelItem);                                                     
 797                          }                                                                                         
 798                          break;                                                                                    
 799                      default:                                                                                      
 800                          break;                                                                                    
 801                  }                                                                                                 
 802              } else {                                                                                              
 803                  sBgWorkspaceItems.remove(modelItem);                                                              
 804              }                                                                                                     
 805          }                                                                                                         
 806      }                                                                                                             
 807                                                                                                                    
 808      /**                                                                                                           
 809       * Move an item in the DB to a new <container, screen, cellX, cellY>                                          
 810       */                                                                                                           
 811      static void moveItemInDatabase(Context context, final ItemInfo item, final long container,                    
 812              final long screenId, final int cellX, final int cellY) {                                              
 813          item.container = container;                                                                               
 814          item.cellX = cellX;                                                                                       
 815          item.cellY = cellY;                                                                                       
 816                                                                                                                    
 817          // We store hotseat items in canonical form which is this orientation invariant position                  
 818          // in the hotseat                                                                                         
 819          if (context instanceof Launcher && screenId < 0 &&                                                        
 820                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 821              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 822          } else {                                                                                                  
 823              item.screenId = screenId;                                                                             
 824          }                                                                                                         
 825                                                                                                                    
 826          final ContentValues values = new ContentValues();                                                         
 827          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 828          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 829          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 830          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
 831          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 832                                                                                                                    
 833          updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                                  
 834      }                                                                                                             
 835                                                                                                                    
 836      /**                                                                                                           
 837       * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the                        
 838       * cellX, cellY have already been updated on the ItemInfos.                                                   
 839       */                                                                                                           
 840      static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                             
 841              final long container, final int screen) {                                                             
 842                                                                                                                    
 843          ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                                  
 844          int count = items.size();                                                                                 
 845                                                                                                                    
 846          for (int i = 0; i < count; i++) {                                                                         
 847              ItemInfo item = items.get(i);                                                                         
 848              item.container = container;                                                                           
 849                                                                                                                    
 850              // We store hotseat items in canonical form which is this orientation invariant position              
 851              // in the hotseat                                                                                     
 852              if (context instanceof Launcher && screen < 0 &&                                                      
 853                      container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                  
 854                  item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,                   
 855                          item.cellY);                                                                              
 856              } else {                                                                                              
 857                  item.screenId = screen;                                                                           
 858              }                                                                                                     
 859                                                                                                                    
 860              final ContentValues values = new ContentValues();                                                     
 861              values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                     
 862              values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                             
 863              values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                             
 864              values.put(LauncherSettings.Favorites.RANK, item.rank);                                               
 865              values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                         
 866                                                                                                                    
 867              contentValues.add(values);                                                                            
 868          }                                                                                                         
 869          updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                         
 870      }                                                                                                             
 871                                                                                                                    
 872      /**                                                                                                           
 873       * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>                 
 874       */                                                                                                           
 875      static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,                  
 876              final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {            
 877          item.container = container;                                                                               
 878          item.cellX = cellX;                                                                                       
 879          item.cellY = cellY;                                                                                       
 880          item.spanX = spanX;                                                                                       
 881          item.spanY = spanY;                                                                                       
 882                                                                                                                    
 883          // We store hotseat items in canonical form which is this orientation invariant position                  
 884          // in the hotseat                                                                                         
 885          if (context instanceof Launcher && screenId < 0 &&                                                        
 886                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 887              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 888          } else {                                                                                                  
 889              item.screenId = screenId;                                                                             
 890          }                                                                                                         
 891                                                                                                                    
 892          final ContentValues values = new ContentValues();                                                         
 893          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 894          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 895          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 896          values.put(LauncherSettings.Favorites.RANK, item.rank);                                                   
 897          values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                                 
 898          values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                                 
 899          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 900                                                                                                                    
 901          updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                                
 902      }                                                                                                             
 903                                                                                                                    
 904      /**                                                                                                           
 905       * Update an item to the database in a specified container.                                                   
 906       */                                                                                                           
 907      static void updateItemInDatabase(Context context, final ItemInfo item) {                                      
 908          final ContentValues values = new ContentValues();                                                         
 909          item.onAddToDatabase(context, values);                                                                    
 910          updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                                
 911      }                                                                                                             
 912                                                                                                                    
 913      /**                                                                                                           
 914       * Returns true if the shortcuts already exists in the database.                                              
 915       * we identify a shortcut by its title and intent.                                                            
 916       */                                                                                                           
 917      static boolean shortcutExists(Context context, String title, Intent intent,                                   
 918              UserHandleCompat user) {                                                                              
 919          final ContentResolver cr = context.getContentResolver();                                                  
 920          final Intent intentWithPkg, intentWithoutPkg;                                                             
 921                                                                                                                    
 922          if (intent.getComponent() != null) {                                                                      
 923              // If component is not null, an intent with null package will produce                                 
 924              // the same result and should also be a match.                                                        
 925              if (intent.getPackage() != null) {                                                                    
 926                  intentWithPkg = intent;                                                                           
 927                  intentWithoutPkg = new Intent(intent).setPackage(null);                                           
 928              } else {                                                                                              
 929                  intentWithPkg = new Intent(intent).setPackage(                                                    
 930                          intent.getComponent().getPackageName());                                                  
 931                  intentWithoutPkg = intent;                                                                        
 932              }                                                                                                     
 933          } else {                                                                                                  
 934              intentWithPkg = intent;                                                                               
 935              intentWithoutPkg = intent;                                                                            
 936          }                                                                                                         
 937          String userSerial = Long.toString(UserManagerCompat.getInstance(context)                                  
 938                  .getSerialNumberForUser(user));                                                                   
 939          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 940              new String[] { "title", "intent", "profileId" },                                                      
 941              "title=? and (intent=? or intent=?) and profileId=?",                                                 
 942              new String[] { title, intentWithPkg.toUri(0), intentWithoutPkg.toUri(0), userSerial },                
 943              null);                                                                                                
 944          try {                                                                                                     
 945              return c.moveToFirst();                                                                               
 946          } finally {                                                                                               
 947              c.close();                                                                                            
 948          }                                                                                                         
 949      }                                                                                                             
 950                                                                                                                    
 951      /**                                                                                                           
 952       * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.                
 953       */                                                                                                           
 954      FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {                     
 955          final ContentResolver cr = context.getContentResolver();                                                  
 956          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                         
 957                  "_id=? and (itemType=? or itemType=?)",                                                           
 958                  new String[] { String.valueOf(id),                                                                
 959                          String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);                      
 960                                                                                                                    
 961          try {                                                                                                     
 962              if (c.moveToFirst()) {                                                                                
 963                  final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);          
 964                  final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);                 
 965                  final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);         
 966                  final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);               
 967                  final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                 
 968                  final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                 
 969                                                                                                                    
 970                  FolderInfo folderInfo = null;                                                                     
 971                  switch (c.getInt(itemTypeIndex)) {                                                                
 972                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 973                          folderInfo = findOrMakeFolder(folderList, id);                                            
 974                          break;                                                                                    
 975                  }                                                                                                 
 976                                                                                                                    
 977                  folderInfo.title = c.getString(titleIndex);                                                       
 978                  folderInfo.id = id;                                                                               
 979                  folderInfo.container = c.getInt(containerIndex);                                                  
 980                  folderInfo.screenId = c.getInt(screenIndex);                                                      
 981                  folderInfo.cellX = c.getInt(cellXIndex);                                                          
 982                  folderInfo.cellY = c.getInt(cellYIndex);                                                          
 983                                                                                                                    
 984                  return folderInfo;                                                                                
 985              }                                                                                                     
 986          } finally {                                                                                               
 987              c.close();                                                                                            
 988          }                                                                                                         
 989                                                                                                                    
 990          return null;                                                                                              
 991      }                                                                                                             
 992                                                                                                                    
 993      /**                                                                                                           
 994       * Add an item to the database in a specified container. Sets the container, screen, cellX and                
 995       * cellY fields of the item. Also assigns an ID to the item.                                                  
 996       */                                                                                                           
 997      static void addItemToDatabase(Context context, final ItemInfo item, final long container,                     
 998              final long screenId, final int cellX, final int cellY, final boolean notify) {                        
 999          item.container = container;                                                                               
1000          item.cellX = cellX;                                                                                       
1001          item.cellY = cellY;                                                                                       
1002          // We store hotseat items in canonical form which is this orientation invariant position                  
1003          // in the hotseat                                                                                         
1004          if (context instanceof Launcher && screenId < 0 &&                                                        
1005                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
1006              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
1007          } else {                                                                                                  
1008              item.screenId = screenId;                                                                             
1009          }                                                                                                         
1010                                                                                                                    
1011          final ContentValues values = new ContentValues();                                                         
1012          final ContentResolver cr = context.getContentResolver();                                                  
1013          item.onAddToDatabase(context, values);                                                                    
1014                                                                                                                    
1015          item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                                     
1016          values.put(LauncherSettings.Favorites._ID, item.id);                                                      
1017                                                                                                                    
1018          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
1019          Runnable r = new Runnable() {                                                                             
1020              public void run() {                                                                                   
1021                  cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                                       
1022                          LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                          
1023                                                                                                                    
1024                  // Lock on mBgLock *after* the db operation                                                       
1025                  synchronized (sBgLock) {                                                                          
1026                      checkItemInfoLocked(item.id, item, stackTrace);                                               
1027                      sBgItemsIdMap.put(item.id, item);                                                             
1028                      switch (item.itemType) {                                                                      
1029                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
1030                              sBgFolders.put(item.id, (FolderInfo) item);                                           
1031                              // Fall through                                                                       
1032                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
1033                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
1034                              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                 
1035                                      item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
1036                                  sBgWorkspaceItems.add(item);                                                      
1037                              } else {                                                                              
1038                                  if (!sBgFolders.containsKey(item.container)) {                                    
1039                                      // Adding an item to a folder that doesn't exist.                             
1040                                      String msg = "adding item: " + item + " to a folder that " +                  
1041                                              " doesn't exist";                                                     
1042                                      Log.e(TAG, msg);                                                              
1043                                  }                                                                                 
1044                              }                                                                                     
1045                              break;                                                                                
1046                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
1047                              sBgAppWidgets.add((LauncherAppWidgetInfo) item);                                      
1048                              break;                                                                                
1049                      }                                                                                             
1050                  }                                                                                                 
1051              }                                                                                                     
1052          };                                                                                                        
1053          runOnWorkerThread(r);                                                                                     
1054      }                                                                                                             
1055                                                                                                                    
1056      /**                                                                                                           
1057       * Creates a new unique child id, for a given cell span across all layouts.                                   
1058       */                                                                                                           
1059      static int getCellLayoutChildId(                                                                              
1060              long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {                  
1061          return (((int) container & 0xFF) << 24)                                                                   
1062                  | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);                   
1063      }                                                                                                             
1064                                                                                                                    
1065      private static ArrayList<ItemInfo> getItemsByPackageName(                                                     
1066              final String pn, final UserHandleCompat user) {                                                       
1067          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
1068              @Override                                                                                             
1069              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
1070                  return cn.getPackageName().equals(pn) && info.user.equals(user);                                  
1071              }                                                                                                     
1072          };                                                                                                        
1073          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
1074      }                                                                                                             
1075                                                                                                                    
1076      /**                                                                                                           
1077       * Removes all the items from the database corresponding to the specified package.                            
1078       */                                                                                                           
1079      static void deletePackageFromDatabase(Context context, final String pn,                                       
1080              final UserHandleCompat user) {                                                                        
1081          deleteItemsFromDatabase(context, getItemsByPackageName(pn, user));                                        
1082      }                                                                                                             
1083                                                                                                                    
1084      /**                                                                                                           
1085       * Removes the specified item from the database                                                               
1086       * @param context                                                                                             
1087       * @param item                                                                                                
1088       */                                                                                                           
1089      static void deleteItemFromDatabase(Context context, final ItemInfo item) {                                    
1090          ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                                    
1091          items.add(item);                                                                                          
1092          deleteItemsFromDatabase(context, items);                                                                  
1093      }                                                                                                             
1094                                                                                                                    
1095      /**                                                                                                           
1096       * Removes the specified items from the database                                                              
1097       * @param context                                                                                             
1098       * @param item                                                                                                
1099       */                                                                                                           
1100      static void deleteItemsFromDatabase(Context context, final ArrayList<? extends ItemInfo> items) {             
1101          final ContentResolver cr = context.getContentResolver();                                                  
1102                                                                                                                    
1103          Runnable r = new Runnable() {                                                                             
1104              public void run() {                                                                                   
1105                  for (ItemInfo item : items) {                                                                     
1106                      final Uri uri = LauncherSettings.Favorites.getContentUri(item.id, false);                     
1107                      cr.delete(uri, null, null);                                                                   
1108                                                                                                                    
1109                      // Lock on mBgLock *after* the db operation                                                   
1110                      synchronized (sBgLock) {                                                                      
1111                          switch (item.itemType) {                                                                  
1112                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
1113                                  sBgFolders.remove(item.id);                                                       
1114                                  for (ItemInfo info: sBgItemsIdMap.values()) {                                     
1115                                      if (info.container == item.id) {                                              
1116                                          // We are deleting a folder which still contains items that               
1117                                          // think they are contained by that folder.                               
1118                                          String msg = "deleting a folder (" + item + ") which still " +            
1119                                                  "contains items (" + info + ")";                                  
1120                                          Log.e(TAG, msg);                                                          
1121                                      }                                                                             
1122                                  }                                                                                 
1123                                  sBgWorkspaceItems.remove(item);                                                   
1124                                  break;                                                                            
1125                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1126                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1127                                  sBgWorkspaceItems.remove(item);                                                   
1128                                  break;                                                                            
1129                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
1130                                  sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                               
1131                                  break;                                                                            
1132                          }                                                                                         
1133                          sBgItemsIdMap.remove(item.id);                                                            
1134                          sBgDbIconCache.remove(item);                                                              
1135                      }                                                                                             
1136                  }                                                                                                 
1137              }                                                                                                     
1138          };                                                                                                        
1139          runOnWorkerThread(r);                                                                                     
1140      }                                                                                                             
1141                                                                                                                    
1142      /**                                                                                                           
1143       * Update the order of the workspace screens in the database. The array list contains                         
1144       * a list of screen ids in the order that they should appear.                                                 
1145       */                                                                                                           
1146      void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                             
1147          // Log to disk                                                                                            
1148          Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                                
1149          Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);                 
1150                                                                                                                    
1151          final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                         
1152          final ContentResolver cr = context.getContentResolver();                                                  
1153          final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                            
1154                                                                                                                    
1155          // Remove any negative screen ids -- these aren't persisted                                               
1156          Iterator<Long> iter = screensCopy.iterator();                                                             
1157          while (iter.hasNext()) {                                                                                  
1158              long id = iter.next();                                                                                
1159              if (id < 0) {                                                                                         
1160                  iter.remove();                                                                                    
1161              }                                                                                                     
1162          }                                                                                                         
1163                                                                                                                    
1164          Runnable r = new Runnable() {                                                                             
1165              @Override                                                                                             
1166              public void run() {                                                                                   
1167                  ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();              
1168                  // Clear the table                                                                                
1169                  ops.add(ContentProviderOperation.newDelete(uri).build());                                         
1170                  int count = screensCopy.size();                                                                   
1171                  for (int i = 0; i < count; i++) {                                                                 
1172                      ContentValues v = new ContentValues();                                                        
1173                      long screenId = screensCopy.get(i);                                                           
1174                      v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                                       
1175                      v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                                      
1176                      ops.add(ContentProviderOperation.newInsert(uri).withValues(v).build());                       
1177                  }                                                                                                 
1178                                                                                                                    
1179                  try {                                                                                             
1180                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
1181                  } catch (Exception ex) {                                                                          
1182                      throw new RuntimeException(ex);                                                               
1183                  }                                                                                                 
1184                                                                                                                    
1185                  synchronized (sBgLock) {                                                                          
1186                      sBgWorkspaceScreens.clear();                                                                  
1187                      sBgWorkspaceScreens.addAll(screensCopy);                                                      
1188                  }                                                                                                 
1189              }                                                                                                     
1190          };                                                                                                        
1191          runOnWorkerThread(r);                                                                                     
1192      }                                                                                                             
1193                                                                                                                    
1194      /**                                                                                                           
1195       * Remove the contents of the specified folder from the database                                              
1196       */                                                                                                           
1197      static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                        
1198          final ContentResolver cr = context.getContentResolver();                                                  
1199                                                                                                                    
1200          Runnable r = new Runnable() {                                                                             
1201              public void run() {                                                                                   
1202                  cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);                  
1203                  // Lock on mBgLock *after* the db operation                                                       
1204                  synchronized (sBgLock) {                                                                          
1205                      sBgItemsIdMap.remove(info.id);                                                                
1206                      sBgFolders.remove(info.id);                                                                   
1207                      sBgDbIconCache.remove(info);                                                                  
1208                      sBgWorkspaceItems.remove(info);                                                               
1209                  }                                                                                                 
1210                                                                                                                    
1211                  cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                 
1212                          LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                              
1213                  // Lock on mBgLock *after* the db operation                                                       
1214                  synchronized (sBgLock) {                                                                          
1215                      for (ItemInfo childInfo : info.contents) {                                                    
1216                          sBgItemsIdMap.remove(childInfo.id);                                                       
1217                          sBgDbIconCache.remove(childInfo);                                                         
1218                      }                                                                                             
1219                  }                                                                                                 
1220              }                                                                                                     
1221          };                                                                                                        
1222          runOnWorkerThread(r);                                                                                     
1223      }                                                                                                             
1224                                                                                                                    
1225      /**                                                                                                           
1226       * Set this as the current Launcher activity object for the loader.                                           
1227       */                                                                                                           
1228      public void initialize(Callbacks callbacks) {                                                                 
1229          synchronized (mLock) {                                                                                    
1230              mCallbacks = new WeakReference<Callbacks>(callbacks);                                                 
1231          }                                                                                                         
1232      }                                                                                                             
1233                                                                                                                    
1234      @Override                                                                                                     
1235      public void onPackageChanged(String packageName, UserHandleCompat user) {                                     
1236          int op = PackageUpdatedTask.OP_UPDATE;                                                                    
1237          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1238                  user));                                                                                           
1239      }                                                                                                             
1240                                                                                                                    
1241      @Override                                                                                                     
1242      public void onPackageRemoved(String packageName, UserHandleCompat user) {                                     
1243          int op = PackageUpdatedTask.OP_REMOVE;                                                                    
1244          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1245                  user));                                                                                           
1246      }                                                                                                             
1247                                                                                                                    
1248      @Override                                                                                                     
1249      public void onPackageAdded(String packageName, UserHandleCompat user) {                                       
1250          int op = PackageUpdatedTask.OP_ADD;                                                                       
1251          enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },                            
1252                  user));                                                                                           
1253      }                                                                                                             
1254                                                                                                                    
1255      @Override                                                                                                     
1256      public void onPackagesAvailable(String[] packageNames, UserHandleCompat user,                                 
1257              boolean replacing) {                                                                                  
1258          if (!replacing) {                                                                                         
1259              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packageNames,                 
1260                      user));                                                                                       
1261              if (mAppsCanBeOnRemoveableStorage) {                                                                  
1262                  // Only rebind if we support removable storage. It catches the                                    
1263                  // case where                                                                                     
1264                  // apps on the external sd card need to be reloaded                                               
1265                  startLoaderFromBackground();                                                                      
1266              }                                                                                                     
1267          } else {                                                                                                  
1268              // If we are replacing then just update the packages in the list                                      
1269              enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                            
1270                      packageNames, user));                                                                         
1271          }                                                                                                         
1272      }                                                                                                             
1273                                                                                                                    
1274      @Override                                                                                                     
1275      public void onPackagesUnavailable(String[] packageNames, UserHandleCompat user,                               
1276              boolean replacing) {                                                                                  
1277          if (!replacing) {                                                                                         
1278              enqueuePackageUpdated(new PackageUpdatedTask(                                                         
1279                      PackageUpdatedTask.OP_UNAVAILABLE, packageNames,                                              
1280                      user));                                                                                       
1281          }                                                                                                         
1282      }                                                                                                             
1283                                                                                                                    
1284      /**                                                                                                           
1285       * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                                 
1286       * ACTION_PACKAGE_CHANGED.                                                                                    
1287       */                                                                                                           
1288      @Override                                                                                                     
1289      public void onReceive(Context context, Intent intent) {                                                       
1290          if (DEBUG_RECEIVER) Log.d(TAG, "onReceive intent=" + intent);                                             
1291                                                                                                                    
1292          final String action = intent.getAction();                                                                 
1293          if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                                        
1294              // If we have changed locale we need to clear out the labels in all apps/workspace.                   
1295              forceReload();                                                                                        
1296          } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                          
1297               // Check if configuration change was an mcc/mnc change which would affect app resources              
1298               // and we would need to clear out the labels in all apps/workspace. Same handling as                 
1299               // above for ACTION_LOCALE_CHANGED                                                                   
1300               Configuration currentConfig = context.getResources().getConfiguration();                             
1301               if (mPreviousConfigMcc != currentConfig.mcc) {                                                       
1302                     Log.d(TAG, "Reload apps on config change. curr_mcc:"                                           
1303                         + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                                   
1304                     forceReload();                                                                                 
1305               }                                                                                                    
1306               // Update previousConfig                                                                             
1307               mPreviousConfigMcc = currentConfig.mcc;                                                              
1308          } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                          
1309                     SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                              
1310              Callbacks callbacks = getCallback();                                                                  
1311              if (callbacks != null) {                                                                              
1312                  callbacks.bindSearchablesChanged();                                                               
1313              }                                                                                                     
1314          }                                                                                                         
1315      }                                                                                                             
1316                                                                                                                    
1317      void forceReload() {                                                                                          
1318          resetLoadedState(true, true);                                                                             
1319                                                                                                                    
1320          // Do this here because if the launcher activity is running it will be restarted.                         
1321          // If it's not running startLoaderFromBackground will merely tell it that it needs                        
1322          // to reload.                                                                                             
1323          startLoaderFromBackground();                                                                              
1324      }                                                                                                             
1325                                                                                                                    
1326      public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {                      
1327          synchronized (mLock) {                                                                                    
1328              // Stop any existing loaders first, so they don't set mAllAppsLoaded or                               
1329              // mWorkspaceLoaded to true later                                                                     
1330              stopLoaderLocked();                                                                                   
1331              if (resetAllAppsLoaded) mAllAppsLoaded = false;                                                       
1332              if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                                   
1333          }                                                                                                         
1334      }                                                                                                             
1335                                                                                                                    
1336      /**                                                                                                           
1337       * When the launcher is in the background, it's possible for it to miss paired                                
1338       * configuration changes.  So whenever we trigger the loader from the background                              
1339       * tell the launcher that it needs to re-run the loader when it comes back instead                            
1340       * of doing it now.                                                                                           
1341       */                                                                                                           
1342      public void startLoaderFromBackground() {                                                                     
1343          boolean runLoader = false;                                                                                
1344          Callbacks callbacks = getCallback();                                                                      
1345          if (callbacks != null) {                                                                                  
1346              // Only actually run the loader if they're not paused.                                                
1347              if (!callbacks.setLoadOnResume()) {                                                                   
1348                  runLoader = true;                                                                                 
1349              }                                                                                                     
1350          }                                                                                                         
1351          if (runLoader) {                                                                                          
1352              startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                                   
1353          }                                                                                                         
1354      }                                                                                                             
1355                                                                                                                    
1356      // If there is already a loader task running, tell it to stop.                                                
1357      // returns true if isLaunching() was true on the old task                                                     
1358      private boolean stopLoaderLocked() {                                                                          
1359          boolean isLaunching = false;                                                                              
1360          LoaderTask oldTask = mLoaderTask;                                                                         
1361          if (oldTask != null) {                                                                                    
1362              if (oldTask.isLaunching()) {                                                                          
1363                  isLaunching = true;                                                                               
1364              }                                                                                                     
1365              oldTask.stopLocked();                                                                                 
1366          }                                                                                                         
1367          return isLaunching;                                                                                       
1368      }                                                                                                             
1369                                                                                                                    
1370      public boolean isCurrentCallbacks(Callbacks callbacks) {                                                      
1371          return (mCallbacks != null && mCallbacks.get() == callbacks);                                             
1372      }                                                                                                             
1373                                                                                                                    
1374      public void startLoader(boolean isLaunching, int synchronousBindPage) {                                       
1375          startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                          
1376      }                                                                                                             
1377                                                                                                                    
1378      public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {                        
1379          synchronized (mLock) {                                                                                    
1380              if (DEBUG_LOADERS) {                                                                                  
1381                  Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                             
1382              }                                                                                                     
1383                                                                                                                    
1384              // Clear any deferred bind-runnables from the synchronized load process                               
1385              // We must do this before any loading/binding is scheduled below.                                     
1386              synchronized (mDeferredBindRunnables) {                                                               
1387                  mDeferredBindRunnables.clear();                                                                   
1388              }                                                                                                     
1389                                                                                                                    
1390              // Don't bother to start the thread if we know it's not going to do anything                          
1391              if (mCallbacks != null && mCallbacks.get() != null) {                                                 
1392                  // If there is already one running, tell it to stop.                                              
1393                  // also, don't downgrade isLaunching if we're already running                                     
1394                  isLaunching = isLaunching || stopLoaderLocked();                                                  
1395                  mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                          
1396                  if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                         
1397                          && mAllAppsLoaded && mWorkspaceLoaded) {                                                  
1398                      mLoaderTask.runBindSynchronousPage(synchronousBindPage);                                      
1399                  } else {                                                                                          
1400                      sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                              
1401                      sWorker.post(mLoaderTask);                                                                    
1402                  }                                                                                                 
1403              }                                                                                                     
1404          }                                                                                                         
1405      }                                                                                                             
1406                                                                                                                    
1407      void bindRemainingSynchronousPages() {                                                                        
1408          // Post the remaining side pages to be loaded                                                             
1409          if (!mDeferredBindRunnables.isEmpty()) {                                                                  
1410              Runnable[] deferredBindRunnables = null;                                                              
1411              synchronized (mDeferredBindRunnables) {                                                               
1412                  deferredBindRunnables = mDeferredBindRunnables.toArray(                                           
1413                          new Runnable[mDeferredBindRunnables.size()]);                                             
1414                  mDeferredBindRunnables.clear();                                                                   
1415              }                                                                                                     
1416              for (final Runnable r : deferredBindRunnables) {                                                      
1417                  mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                                   
1418              }                                                                                                     
1419          }                                                                                                         
1420      }                                                                                                             
1421                                                                                                                    
1422      public void stopLoader() {                                                                                    
1423          synchronized (mLock) {                                                                                    
1424              if (mLoaderTask != null) {                                                                            
1425                  mLoaderTask.stopLocked();                                                                         
1426              }                                                                                                     
1427          }                                                                                                         
1428      }                                                                                                             
1429                                                                                                                    
1430      /**                                                                                                           
1431       * Loads the workspace screen ids in an ordered list.                                                         
1432       */                                                                                                           
1433      private static ArrayList<Long> loadWorkspaceScreensDb(Context context) {                                      
1434          final ContentResolver contentResolver = context.getContentResolver();                                     
1435          final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                     
1436                                                                                                                    
1437          // Get screens ordered by rank.                                                                           
1438          final Cursor sc = contentResolver.query(screensUri, null, null, null,                                     
1439                  LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                                   
1440          ArrayList<Long> screenIds = new ArrayList<Long>();                                                        
1441          try {                                                                                                     
1442              final int idIndex = sc.getColumnIndexOrThrow(LauncherSettings.WorkspaceScreens._ID);                  
1443              while (sc.moveToNext()) {                                                                             
1444                  try {                                                                                             
1445                      screenIds.add(sc.getLong(idIndex));                                                           
1446                  } catch (Exception e) {                                                                           
1447                      Launcher.addDumpLog(TAG, "Desktop items loading interrupted"                                  
1448                              + " - invalid screens: " + e, true);                                                  
1449                  }                                                                                                 
1450              }                                                                                                     
1451          } finally {                                                                                               
1452              sc.close();                                                                                           
1453          }                                                                                                         
1454          return screenIds;                                                                                         
1455      }                                                                                                             
1456                                                                                                                    
1457      public boolean isAllAppsLoaded() {                                                                            
1458          return mAllAppsLoaded;                                                                                    
1459      }                                                                                                             
1460                                                                                                                    
1461      boolean isLoadingWorkspace() {                                                                                
1462          synchronized (mLock) {                                                                                    
1463              if (mLoaderTask != null) {                                                                            
1464                  return mLoaderTask.isLoadingWorkspace();                                                          
1465              }                                                                                                     
1466          }                                                                                                         
1467          return false;                                                                                             
1468      }                                                                                                             
1469                                                                                                                    
1470      /**                                                                                                           
1471       * Runnable for the thread that loads the contents of the launcher:                                           
1472       *   - workspace icons                                                                                        
1473       *   - widgets                                                                                                
1474       *   - all apps icons                                                                                         
1475       */                                                                                                           
1476      private class LoaderTask implements Runnable {                                                                
1477          private Context mContext;                                                                                 
1478          private boolean mIsLaunching;                                                                             
1479          private boolean mIsLoadingAndBindingWorkspace;                                                            
1480          private boolean mStopped;                                                                                 
1481          private boolean mLoadAndBindStepFinished;                                                                 
1482          private int mFlags;                                                                                       
1483                                                                                                                    
1484          private HashMap<Object, CharSequence> mLabelCache;                                                        
1485                                                                                                                    
1486          LoaderTask(Context context, boolean isLaunching, int flags) {                                             
1487              mContext = context;                                                                                   
1488              mIsLaunching = isLaunching;                                                                           
1489              mLabelCache = new HashMap<Object, CharSequence>();                                                    
1490              mFlags = flags;                                                                                       
1491          }                                                                                                         
1492                                                                                                                    
1493          boolean isLaunching() {                                                                                   
1494              return mIsLaunching;                                                                                  
1495          }                                                                                                         
1496                                                                                                                    
1497          boolean isLoadingWorkspace() {                                                                            
1498              return mIsLoadingAndBindingWorkspace;                                                                 
1499          }                                                                                                         
1500                                                                                                                    
1501          private void loadAndBindWorkspace() {                                                                     
1502              mIsLoadingAndBindingWorkspace = true;                                                                 
1503                                                                                                                    
1504              // Load the workspace                                                                                 
1505              if (DEBUG_LOADERS) {                                                                                  
1506                  Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                          
1507              }                                                                                                     
1508                                                                                                                    
1509              if (!mWorkspaceLoaded) {                                                                              
1510                  loadWorkspace();                                                                                  
1511                  synchronized (LoaderTask.this) {                                                                  
1512                      if (mStopped) {                                                                               
1513                          return;                                                                                   
1514                      }                                                                                             
1515                      mWorkspaceLoaded = true;                                                                      
1516                  }                                                                                                 
1517              }                                                                                                     
1518                                                                                                                    
1519              // Bind the workspace                                                                                 
1520              bindWorkspace(-1);                                                                                    
1521          }                                                                                                         
1522                                                                                                                    
1523          private void waitForIdle() {                                                                              
1524              // Wait until the either we're stopped or the other threads are done.                                 
1525              // This way we don't start loading all apps until the workspace has settled                           
1526              // down.                                                                                              
1527              synchronized (LoaderTask.this) {                                                                      
1528                  final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    
1529                                                                                                                    
1530                  mHandler.postIdle(new Runnable() {                                                                
1531                          public void run() {                                                                       
1532                              synchronized (LoaderTask.this) {                                                      
1533                                  mLoadAndBindStepFinished = true;                                                  
1534                                  if (DEBUG_LOADERS) {                                                              
1535                                      Log.d(TAG, "done with previous binding step");                                
1536                                  }                                                                                 
1537                                  LoaderTask.this.notify();                                                         
1538                              }                                                                                     
1539                          }                                                                                         
1540                      });                                                                                           
1541                                                                                                                    
1542                  while (!mStopped && !mLoadAndBindStepFinished) {                                                  
1543                      try {                                                                                         
1544                          // Just in case mFlushingWorkerThread changes but we aren't woken up,                     
1545                          // wait no longer than 1sec at a time                                                     
1546                          this.wait(1000);                                                                          
1547                      } catch (InterruptedException ex) {                                                           
1548                          // Ignore                                                                                 
1549                      }                                                                                             
1550                  }                                                                                                 
1551                  if (DEBUG_LOADERS) {                                                                              
1552                      Log.d(TAG, "waited "                                                                          
1553                              + (SystemClock.uptimeMillis()-workspaceWaitTime)                                      
1554                              + "ms for previous step to finish binding");                                          
1555                  }                                                                                                 
1556              }                                                                                                     
1557          }                                                                                                         
1558                                                                                                                    
1559          void runBindSynchronousPage(int synchronousBindPage) {                                                    
1560              if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                          
1561                  // Ensure that we have a valid page index to load synchronously                                   
1562                  throw new RuntimeException("Should not call runBindSynchronousPage() without " +                  
1563                          "valid page index");                                                                      
1564              }                                                                                                     
1565              if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                           
1566                  // Ensure that we don't try and bind a specified page when the pages have not been                
1567                  // loaded already (we should load everything asynchronously in that case)                         
1568                  throw new RuntimeException("Expecting AllApps and Workspace to be loaded");                       
1569              }                                                                                                     
1570              synchronized (mLock) {                                                                                
1571                  if (mIsLoaderTaskRunning) {                                                                       
1572                      // Ensure that we are never running the background loading at this point since                
1573                      // we also touch the background collections                                                   
1574                      throw new RuntimeException("Error! Background loading is already running");                   
1575                  }                                                                                                 
1576              }                                                                                                     
1577                                                                                                                    
1578              // XXX: Throw an exception if we are already loading (since we touch the worker thread                
1579              //      data structures, we can't allow any other thread to touch that data, but because              
1580              //      this call is synchronous, we can get away with not locking).                                  
1581                                                                                                                    
1582              // The LauncherModel is static in the LauncherAppState and mHandler may have queued                   
1583              // operations from the previous activity.  We need to ensure that all queued operations               
1584              // are executed before any synchronous binding work is done.                                          
1585              mHandler.flush();                                                                                     
1586                                                                                                                    
1587              // Divide the set of loaded items into those that we are binding synchronously, and                   
1588              // everything else that is to be bound normally (asynchronously).                                     
1589              bindWorkspace(synchronousBindPage);                                                                   
1590              // XXX: For now, continue posting the binding of AllApps as there are other issues that               
1591              //      arise from that.                                                                              
1592              onlyBindAllApps();                                                                                    
1593          }                                                                                                         
1594                                                                                                                    
1595          public void run() {                                                                                       
1596              synchronized (mLock) {                                                                                
1597                  mIsLoaderTaskRunning = true;                                                                      
1598              }                                                                                                     
1599              // Optimize for end-user experience: if the Launcher is up and // running with the                    
1600              // All Apps interface in the foreground, load All Apps first. Otherwise, load the                     
1601              // workspace first (default).                                                                         
1602              keep_running: {                                                                                       
1603                  // Elevate priority when Home launches for the first time to avoid                                
1604                  // starving at boot time. Staring at a blank home is not cool.                                    
1605                  synchronized (mLock) {                                                                            
1606                      if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                                 
1607                              (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                           
1608                      android.os.Process.setThreadPriority(mIsLaunching                                             
1609                              ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);              
1610                  }                                                                                                 
1611                  if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                                       
1612                  loadAndBindWorkspace();                                                                           
1613                                                                                                                    
1614                  if (mStopped) {                                                                                   
1615                      break keep_running;                                                                           
1616                  }                                                                                                 
1617                                                                                                                    
1618                  // Whew! Hard work done.  Slow us down, and wait until the UI thread has                          
1619                  // settled down.                                                                                  
1620                  synchronized (mLock) {                                                                            
1621                      if (mIsLaunching) {                                                                           
1622                          if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                   
1623                          android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                 
1624                      }                                                                                             
1625                  }                                                                                                 
1626                  waitForIdle();                                                                                    
1627                                                                                                                    
1628                  // second step                                                                                    
1629                  if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                                        
1630                  loadAndBindAllApps();                                                                             
1631                                                                                                                    
1632                  // Restore the default thread priority after we are done loading items                            
1633                  synchronized (mLock) {                                                                            
1634                      android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                        
1635                  }                                                                                                 
1636              }                                                                                                     
1637                                                                                                                    
1638              // Update the saved icons if necessary                                                                
1639              if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                            
1640              synchronized (sBgLock) {                                                                              
1641                  for (Object key : sBgDbIconCache.keySet()) {                                                      
1642                      updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));                       
1643                  }                                                                                                 
1644                  sBgDbIconCache.clear();                                                                           
1645              }                                                                                                     
1646                                                                                                                    
1647 -            if (LauncherAppState.isDisableAllApps()) {                                                            
1648 -                // Ensure that all the applications that are in the system are                                    
1649 -                // represented on the home screen.                                                                
1650 -                verifyApplications();                                                                             
1651 -            }                                                                                                     
1652 -                                                                                                                  
1653              // Clear out this reference, otherwise we end up holding it until all of the                          
1654              // callback runnables are done.                                                                       
1655              mContext = null;                                                                                      
1656                                                                                                                    
1657              synchronized (mLock) {                                                                                
1658                  // If we are still the last one to be scheduled, remove ourselves.                                
1659                  if (mLoaderTask == this) {                                                                        
1660                      mLoaderTask = null;                                                                           
1661                  }                                                                                                 
1662                  mIsLoaderTaskRunning = false;                                                                     
1663              }                                                                                                     
1664          }                                                                                                         
1665                                                                                                                    
1666          public void stopLocked() {                                                                                
1667              synchronized (LoaderTask.this) {                                                                      
1668                  mStopped = true;                                                                                  
1669                  this.notify();                                                                                    
1670              }                                                                                                     
1671          }                                                                                                         
1672                                                                                                                    
1673          /**                                                                                                       
1674           * Gets the callbacks object.  If we've been stopped, or if the launcher object                           
1675           * has somehow been garbage collected, return null instead.  Pass in the Callbacks                        
1676           * object that was around when the deferred message was scheduled, and if there's                         
1677           * a new Callbacks object around then also return null.  This will save us from                           
1678           * calling onto it with data that will be ignored.                                                        
1679           */                                                                                                       
1680          Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                                       
1681              synchronized (mLock) {                                                                                
1682                  if (mStopped) {                                                                                   
1683                      return null;                                                                                  
1684                  }                                                                                                 
1685                                                                                                                    
1686                  if (mCallbacks == null) {                                                                         
1687                      return null;                                                                                  
1688                  }                                                                                                 
1689                                                                                                                    
1690                  final Callbacks callbacks = mCallbacks.get();                                                     
1691                  if (callbacks != oldCallbacks) {                                                                  
1692                      return null;                                                                                  
1693                  }                                                                                                 
1694                  if (callbacks == null) {                                                                          
1695                      Log.w(TAG, "no mCallbacks");                                                                  
1696                      return null;                                                                                  
1697                  }                                                                                                 
1698                                                                                                                    
1699                  return callbacks;                                                                                 
1700 -            }                                                                                                     
1701 -        }                                                                                                         
1702 -                                                                                                                  
1703 -        private void verifyApplications() {                                                                       
1704 -            final Context context = mApp.getContext();                                                            
1705 -                                                                                                                  
1706 -            // Cross reference all the applications in our apps list with items in the workspace                  
1707 -            ArrayList<ItemInfo> tmpInfos;                                                                         
1708 -            ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                                
1709 -            synchronized (sBgLock) {                                                                              
1710 -                for (AppInfo app : mBgAllAppsList.data) {                                                         
1711 -                    tmpInfos = getItemInfoForComponentName(app.componentName, app.user);                          
1712 -                    if (tmpInfos.isEmpty()) {                                                                     
1713 -                        // We are missing an application icon, so add this to the workspace                       
1714 -                        added.add(app);                                                                           
1715 -                        // This is a rare event, so lets log it                                                   
1716 -                        Log.e(TAG, "Missing Application on load: " + app);                                        
1717 -                    }                                                                                             
1718 -                }                                                                                                 
1719 -            }                                                                                                     
1720 -            if (!added.isEmpty()) {                                                                               
1721 -                addAndBindAddedWorkspaceApps(context, added);                                                     
1722              }                                                                                                     
1723          }                                                                                                         
1724                                                                                                                    
1725          // check & update map of what's occupied; used to discard overlapping/invalid items                       
1726          private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {                 
1727              LauncherAppState app = LauncherAppState.getInstance();                                                
1728              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1729              final int countX = (int) grid.numColumns;                                                             
1730              final int countY = (int) grid.numRows;                                                                
1731                                                                                                                    
1732              long containerIndex = item.screenId;                                                                  
1733              if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1734                  // Return early if we detect that an item is under the hotseat button                             
1735                  if (mCallbacks == null ||                                                                         
1736                          mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                              
1737                      Log.e(TAG, "Error loading shortcut into hotseat " + item                                      
1738                              + " into position (" + item.screenId + ":" + item.cellX + ","                         
1739                              + item.cellY + ") occupied by all apps");                                             
1740                      return false;                                                                                 
1741                  }                                                                                                 
1742                                                                                                                    
1743                  final ItemInfo[][] hotseatItems =                                                                 
1744                          occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);                        
1745                                                                                                                    
1746                  if (item.screenId >= grid.numHotseatIcons) {                                                      
1747                      Log.e(TAG, "Error loading shortcut " + item                                                   
1748                              + " into hotseat position " + item.screenId                                           
1749                              + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)                     
1750                              + ")");                                                                               
1751                      return false;                                                                                 
1752                  }                                                                                                 
1753                                                                                                                    
1754                  if (hotseatItems != null) {                                                                       
1755                      if (hotseatItems[(int) item.screenId][0] != null) {                                           
1756                          Log.e(TAG, "Error loading shortcut into hotseat " + item                                  
1757                                  + " into position (" + item.screenId + ":" + item.cellX + ","                     
1758                                  + item.cellY + ") occupied by "                                                   
1759                                  + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)                      
1760                                  [(int) item.screenId][0]);                                                        
1761                              return false;                                                                         
1762                      } else {                                                                                      
1763                          hotseatItems[(int) item.screenId][0] = item;                                              
1764                          return true;                                                                              
1765                      }                                                                                             
1766                  } else {                                                                                          
1767                      final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];                       
1768                      items[(int) item.screenId][0] = item;                                                         
1769                      occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);                     
1770                      return true;                                                                                  
1771                  }                                                                                                 
1772              } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                          
1773                  // Skip further checking if it is not the hotseat or workspace container                          
1774                  return true;                                                                                      
1775              }                                                                                                     
1776                                                                                                                    
1777              if (!occupied.containsKey(item.screenId)) {                                                           
1778                  ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                                        
1779                  occupied.put(item.screenId, items);                                                               
1780              }                                                                                                     
1781                                                                                                                    
1782              final ItemInfo[][] screens = occupied.get(item.screenId);                                             
1783              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
1784                      item.cellX < 0 || item.cellY < 0 ||                                                           
1785                      item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {                       
1786                  Log.e(TAG, "Error loading shortcut " + item                                                       
1787                          + " into cell (" + containerIndex + "-" + item.screenId + ":"                             
1788                          + item.cellX + "," + item.cellY                                                           
1789                          + ") out of screen bounds ( " + countX + "x" + countY + ")");                             
1790                  return false;                                                                                     
1791              }                                                                                                     
1792                                                                                                                    
1793              // Check if any workspace icons overlap with each other                                               
1794              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1795                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1796                      if (screens[x][y] != null) {                                                                  
1797                          Log.e(TAG, "Error loading shortcut " + item                                               
1798                              + " into cell (" + containerIndex + "-" + item.screenId + ":"                         
1799                              + x + "," + y                                                                         
1800                              + ") occupied by "                                                                    
1801                              + screens[x][y]);                                                                     
1802                          return false;                                                                             
1803                      }                                                                                             
1804                  }                                                                                                 
1805              }                                                                                                     
1806              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1807                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1808                      screens[x][y] = item;                                                                         
1809                  }                                                                                                 
1810              }                                                                                                     
1811                                                                                                                    
1812              return true;                                                                                          
1813          }                                                                                                         
1814                                                                                                                    
1815          /** Clears all the sBg data structures */                                                                 
1816          private void clearSBgDataStructures() {                                                                   
1817              synchronized (sBgLock) {                                                                              
1818                  sBgWorkspaceItems.clear();                                                                        
1819                  sBgAppWidgets.clear();                                                                            
1820                  sBgFolders.clear();                                                                               
1821                  sBgItemsIdMap.clear();                                                                            
1822                  sBgDbIconCache.clear();                                                                           
1823                  sBgWorkspaceScreens.clear();                                                                      
1824              }                                                                                                     
1825          }                                                                                                         
1826                                                                                                                    
1827          private void loadWorkspace() {                                                                            
1828              // Log to disk                                                                                        
1829              Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                         
1830                                                                                                                    
1831              final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                        
1832                                                                                                                    
1833              final Context context = mContext;                                                                     
1834              final ContentResolver contentResolver = context.getContentResolver();                                 
1835              final PackageManager manager = context.getPackageManager();                                           
1836              final boolean isSafeMode = manager.isSafeMode();                                                      
1837              final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                      
1838              final boolean isSdCardReady = context.registerReceiver(null,                                          
1839                      new IntentFilter(StartupReceiver.SYSTEM_READY)) != null;                                      
1840                                                                                                                    
1841              LauncherAppState app = LauncherAppState.getInstance();                                                
1842              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1843              int countX = (int) grid.numColumns;                                                                   
1844              int countY = (int) grid.numRows;                                                                      
1845                                                                                                                    
1846              if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                                    
1847                  Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);                     
1848                  LauncherAppState.getLauncherProvider().deleteDatabase();                                          
1849              }                                                                                                     
1850                                                                                                                    
1851              if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                                  
1852                  // append the user's Launcher2 shortcuts                                                          
1853                  Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);                        
1854                  LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                               
1855              } else {                                                                                              
1856                  // Make sure the default workspace is loaded                                                      
1857                  Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);                      
1858                  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary();                         
1859              }                                                                                                     
1860                                                                                                                    
1861              synchronized (sBgLock) {                                                                              
1862                  clearSBgDataStructures();                                                                         
1863                  final HashSet<String> installingPkgs = PackageInstallerCompat                                     
1864                          .getInstance(mContext).updateAndGetActiveSessionCache();                                  
1865                                                                                                                    
1866                  final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                                      
1867                  final ArrayList<Long> restoredRows = new ArrayList<Long>();                                       
1868                  final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION;                    
1869                  if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                                
1870                  final Cursor c = contentResolver.query(contentUri, null, null, null, null);                       
1871                                                                                                                    
1872                  // +1 for the hotseat (it can be larger than the workspace)                                       
1873                  // Load workspace in reverse order to ensure that latest items are loaded first (and              
1874                  // before any earlier duplicates)                                                                 
1875                  final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();                   
1876                                                                                                                    
1877                  try {                                                                                             
1878                      final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);                  
1879                      final int intentIndex = c.getColumnIndexOrThrow                                               
1880                              (LauncherSettings.Favorites.INTENT);                                                  
1881                      final int titleIndex = c.getColumnIndexOrThrow                                                
1882                              (LauncherSettings.Favorites.TITLE);                                                   
1883                      final int iconTypeIndex = c.getColumnIndexOrThrow(                                            
1884                              LauncherSettings.Favorites.ICON_TYPE);                                                
1885                      final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);               
1886                      final int iconPackageIndex = c.getColumnIndexOrThrow(                                         
1887                              LauncherSettings.Favorites.ICON_PACKAGE);                                             
1888                      final int iconResourceIndex = c.getColumnIndexOrThrow(                                        
1889                              LauncherSettings.Favorites.ICON_RESOURCE);                                            
1890                      final int containerIndex = c.getColumnIndexOrThrow(                                           
1891                              LauncherSettings.Favorites.CONTAINER);                                                
1892                      final int itemTypeIndex = c.getColumnIndexOrThrow(                                            
1893                              LauncherSettings.Favorites.ITEM_TYPE);                                                
1894                      final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                         
1895                              LauncherSettings.Favorites.APPWIDGET_ID);                                             
1896                      final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                                   
1897                              LauncherSettings.Favorites.APPWIDGET_PROVIDER);                                       
1898                      final int screenIndex = c.getColumnIndexOrThrow(                                              
1899                              LauncherSettings.Favorites.SCREEN);                                                   
1900                      final int cellXIndex = c.getColumnIndexOrThrow                                                
1901                              (LauncherSettings.Favorites.CELLX);                                                   
1902                      final int cellYIndex = c.getColumnIndexOrThrow                                                
1903                              (LauncherSettings.Favorites.CELLY);                                                   
1904                      final int spanXIndex = c.getColumnIndexOrThrow                                                
1905                              (LauncherSettings.Favorites.SPANX);                                                   
1906                      final int spanYIndex = c.getColumnIndexOrThrow(                                               
1907                              LauncherSettings.Favorites.SPANY);                                                    
1908                      final int rankIndex = c.getColumnIndexOrThrow(                                                
1909                              LauncherSettings.Favorites.RANK);                                                     
1910                      final int restoredIndex = c.getColumnIndexOrThrow(                                            
1911                              LauncherSettings.Favorites.RESTORED);                                                 
1912                      final int profileIdIndex = c.getColumnIndexOrThrow(                                           
1913                              LauncherSettings.Favorites.PROFILE_ID);                                               
1914                      //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);               
1915                      //final int displayModeIndex = c.getColumnIndexOrThrow(                                       
1916                      //        LauncherSettings.Favorites.DISPLAY_MODE);                                           
1917                                                                                                                    
1918                      ShortcutInfo info;                                                                            
1919                      String intentDescription;                                                                     
1920                      LauncherAppWidgetInfo appWidgetInfo;                                                          
1921                      int container;                                                                                
1922                      long id;                                                                                      
1923                      Intent intent;                                                                                
1924                      UserHandleCompat user;                                                                        
1925                                                                                                                    
1926                      while (!mStopped && c.moveToNext()) {                                                         
1927                          try {                                                                                     
1928                              int itemType = c.getInt(itemTypeIndex);                                               
1929                              boolean restored = 0 != c.getInt(restoredIndex);                                      
1930                              boolean allowMissingTarget = false;                                                   
1931                                                                                                                    
1932                              switch (itemType) {                                                                   
1933                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1934                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1935                                  id = c.getLong(idIndex);                                                          
1936                                  intentDescription = c.getString(intentIndex);                                     
1937                                  long serialNumber = c.getInt(profileIdIndex);                                     
1938                                  user = mUserManager.getUserForSerialNumber(serialNumber);                         
1939                                  int promiseType = c.getInt(restoredIndex);                                        
1940                                  int disabledState = 0;                                                            
1941                                  boolean itemReplaced = false;                                                     
1942                                  if (user == null) {                                                               
1943                                      // User has been deleted remove the item.                                     
1944                                      itemsToRemove.add(id);                                                        
1945                                      continue;                                                                     
1946                                  }                                                                                 
1947                                  try {                                                                             
1948                                      intent = Intent.parseUri(intentDescription, 0);                               
1949                                      ComponentName cn = intent.getComponent();                                     
1950                                      if (cn != null && cn.getPackageName() != null) {                              
1951                                          boolean validPkg = launcherApps.isPackageEnabledForProfile(               
1952                                                  cn.getPackageName(), user);                                       
1953                                          boolean validComponent = validPkg &&                                      
1954                                                  launcherApps.isActivityEnabledForProfile(cn, user);               
1955                                                                                                                    
1956                                          if (validComponent) {                                                     
1957                                              if (restored) {                                                       
1958                                                  // no special handling necessary for this item                    
1959                                                  restoredRows.add(id);                                             
1960                                                  restored = false;                                                 
1961                                              }                                                                     
1962                                          } else if (validPkg) {                                                    
1963                                              intent = null;                                                        
1964                                              if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {         
1965                                                  // We allow auto install apps to have their intent                
1966                                                  // updated after an install.                                      
1967                                                  intent = manager.getLaunchIntentForPackage(                       
1968                                                          cn.getPackageName());                                     
1969                                                  if (intent != null) {                                             
1970                                                      ContentValues values = new ContentValues();                   
1971                                                      values.put(LauncherSettings.Favorites.INTENT,                 
1972                                                              intent.toUri(0));                                     
1973                                                      updateItem(id, values);                                       
1974                                                  }                                                                 
1975                                              }                                                                     
1976                                                                                                                    
1977                                              if (intent == null) {                                                 
1978                                                  // The app is installed but the component is no                   
1979                                                  // longer available.                                              
1980                                                  Launcher.addDumpLog(TAG,                                          
1981                                                          "Invalid component removed: " + cn, true);                
1982                                                  itemsToRemove.add(id);                                            
1983                                                  continue;                                                         
1984                                              } else {                                                              
1985                                                  // no special handling necessary for this item                    
1986                                                  restoredRows.add(id);                                             
1987                                                  restored = false;                                                 
1988                                              }                                                                     
1989                                          } else if (restored) {                                                    
1990                                              // Package is not yet available but might be                          
1991                                              // installed later.                                                   
1992                                              Launcher.addDumpLog(TAG,                                              
1993                                                      "package not yet restored: " + cn, true);                     
1994                                                                                                                    
1995                                              if ((promiseType & ShortcutInfo.FLAG_RESTORE_STARTED) != 0) {         
1996                                                  // Restore has started once.                                      
1997                                              } else if (installingPkgs.contains(cn.getPackageName())) {            
1998                                                  // App restore has started. Update the flag                       
1999                                                  promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;                 
2000                                                  ContentValues values = new ContentValues();                       
2001                                                  values.put(LauncherSettings.Favorites.RESTORED,                   
2002                                                          promiseType);                                             
2003                                                  updateItem(id, values);                                           
2004                                              } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
2005                                                  // This is a common app. Try to replace this.                     
2006                                                  int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseTy🔵
2007                                                  CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, 🔵
2008                                                  if (parser.findDefaultApp()) {                                    
2009                                                      // Default app found. Replace it.                             
2010                                                      intent = parser.parsedIntent;                                 
2011                                                      cn = intent.getComponent();                                   
2012                                                      ContentValues values = parser.parsedValues;                   
2013                                                      values.put(LauncherSettings.Favorites.RESTORED, 0);           
2014                                                      updateItem(id, values);                                       
2015                                                      restored = false;                                             
2016                                                      itemReplaced = true;                                          
2017                                                                                                                    
2018                                                  } else if (REMOVE_UNRESTORED_ICONS) {                             
2019                                                      Launcher.addDumpLog(TAG,                                      
2020                                                              "Unrestored package removed: " + cn, true);           
2021                                                      itemsToRemove.add(id);                                        
2022                                                      continue;                                                     
2023                                                  }                                                                 
2024                                              } else if (REMOVE_UNRESTORED_ICONS) {                                 
2025                                                  Launcher.addDumpLog(TAG,                                          
2026                                                          "Unrestored package removed: " + cn, true);               
2027                                                  itemsToRemove.add(id);                                            
2028                                                  continue;                                                         
2029                                              }                                                                     
2030                                          } else if (launcherApps.isAppEnabled(                                     
2031                                                  manager, cn.getPackageName(),                                     
2032                                                  PackageManager.GET_UNINSTALLED_PACKAGES)) {                       
2033                                              // Package is present but not available.                              
2034                                              allowMissingTarget = true;                                            
2035                                              disabledState = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;             
2036                                          } else if (!isSdCardReady) {                                              
2037                                              // SdCard is not ready yet. Package might get available,              
2038                                              // once it is ready.                                                  
2039                                              Launcher.addDumpLog(TAG, "Invalid package: " + cn                     
2040                                                      + " (check again later)", true);                              
2041                                              HashSet<String> pkgs = sPendingPackages.get(user);                    
2042                                              if (pkgs == null) {                                                   
2043                                                  pkgs = new HashSet<String>();                                     
2044                                                  sPendingPackages.put(user, pkgs);                                 
2045                                              }                                                                     
2046                                              pkgs.add(cn.getPackageName());                                        
2047                                              allowMissingTarget = true;                                            
2048                                              // Add the icon on the workspace anyway.                              
2049                                                                                                                    
2050                                          } else {                                                                  
2051                                              // Do not wait for external media load anymore.                       
2052                                              // Log the invalid package, and remove it                             
2053                                              Launcher.addDumpLog(TAG,                                              
2054                                                      "Invalid package removed: " + cn, true);                      
2055                                              itemsToRemove.add(id);                                                
2056                                              continue;                                                             
2057                                          }                                                                         
2058                                      } else if (cn == null) {                                                      
2059                                          // For shortcuts with no component, keep them as they are                 
2060                                          restoredRows.add(id);                                                     
2061                                          restored = false;                                                         
2062                                      }                                                                             
2063                                  } catch (URISyntaxException e) {                                                  
2064                                      Launcher.addDumpLog(TAG,                                                      
2065                                              "Invalid uri: " + intentDescription, true);                           
2066                                      continue;                                                                     
2067                                  }                                                                                 
2068                                                                                                                    
2069                                  if (itemReplaced) {                                                               
2070                                      if (user.equals(UserHandleCompat.myUserHandle())) {                           
2071                                          info = getShortcutInfo(manager, intent, user, context, null,              
2072                                                  iconIndex, titleIndex, mLabelCache, false);                       


2073                                      } else {                                                                      
2074                                          // Don't replace items for other profiles.                                
2075                                          itemsToRemove.add(id);                                                    
2076                                          continue;                                                                 
2077                                      }                                                                             
2078                                  } else if (restored) {                                                            
2079                                      if (user.equals(UserHandleCompat.myUserHandle())) {                           
2080                                          Launcher.addDumpLog(TAG,                                                  
2081                                                  "constructing info for partially restored package",               
2082                                                  true);                                                            
2083                                          info = getRestoredItemInfo(c, titleIndex, intent, promiseType);           
2084                                          intent = getRestoredItemIntent(c, context, intent);                       
2085                                      } else {                                                                      
2086                                          // Don't restore items for other profiles.                                
2087                                          itemsToRemove.add(id);                                                    
2088                                          continue;                                                                 
2089                                      }                                                                             
2090                                  } else if (itemType ==                                                            
2091                                          LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                       
2092                                      info = getShortcutInfo(manager, intent, user, context, c,                     
2093                                              iconIndex, titleIndex, mLabelCache, allowMissingTarget);              


2094                                  } else {                                                                          
2095                                      info = getShortcutInfo(c, context, iconTypeIndex,                             
2096                                              iconPackageIndex, iconResourceIndex, iconIndex,                       
2097                                              titleIndex);                                                          
2098                                                                                                                    
2099                                      // App shortcuts that used to be automatically added to Launcher              
2100                                      // didn't always have the correct intent flags set, so do that                
2101                                      // here                                                                       
2102                                      if (intent.getAction() != null &&                                             
2103                                          intent.getCategories() != null &&                                         
2104                                          intent.getAction().equals(Intent.ACTION_MAIN) &&                          
2105                                          intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {              
2106                                          intent.addFlags(                                                          
2107                                              Intent.FLAG_ACTIVITY_NEW_TASK |                                       
2108                                              Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                           
2109                                      }                                                                             
2110                                  }                                                                                 
2111                                                                                                                    
2112                                  if (info != null) {                                                               
2113                                      info.id = id;                                                                 
2114                                      info.intent = intent;                                                         
2115                                      container = c.getInt(containerIndex);                                         
2116                                      info.container = container;                                                   
2117                                      info.screenId = c.getInt(screenIndex);                                        
2118                                      info.cellX = c.getInt(cellXIndex);                                            
2119                                      info.cellY = c.getInt(cellYIndex);                                            
2120                                      info.rank = c.getInt(rankIndex);                                              
2121                                      info.spanX = 1;                                                               
2122                                      info.spanY = 1;                                                               
2123                                      info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);                   
2124                                      info.isDisabled = disabledState;                                              
2125                                      if (isSafeMode && !Utilities.isSystemApp(context, intent)) {                  
2126                                          info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;                   
2127                                      }                                                                             
2128                                                                                                                    
2129                                      // check & update map of what's occupied                                      
2130                                      if (!checkItemPlacement(occupied, info)) {                                    
2131                                          itemsToRemove.add(id);                                                    
2132                                          break;                                                                    
2133                                      }                                                                             
2134                                                                                                                    
2135                                      switch (container) {                                                          
2136                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2137                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2138                                          sBgWorkspaceItems.add(info);                                              
2139                                          break;                                                                    
2140                                      default:                                                                      
2141                                          // Item is in a user folder                                               
2142                                          FolderInfo folderInfo =                                                   
2143                                                  findOrMakeFolder(sBgFolders, container);                          
2144                                          folderInfo.add(info);                                                     
2145                                          break;                                                                    
2146                                      }                                                                             
2147                                      sBgItemsIdMap.put(info.id, info);                                             
2148                                                                                                                    
2149                                      // now that we've loaded everthing re-save it with the                        
2150                                      // icon in case it disappears somehow.                                        
2151                                      queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);                     
2152                                  } else {                                                                          
2153                                      throw new RuntimeException("Unexpected null ShortcutInfo");                   
2154                                  }                                                                                 
2155                                  break;                                                                            
2156                                                                                                                    
2157                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
2158                                  id = c.getLong(idIndex);                                                          
2159                                  FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                         
2160                                                                                                                    
2161                                  folderInfo.title = c.getString(titleIndex);                                       
2162                                  folderInfo.id = id;                                                               
2163                                  container = c.getInt(containerIndex);                                             
2164                                  folderInfo.container = container;                                                 
2165                                  folderInfo.screenId = c.getInt(screenIndex);                                      
2166                                  folderInfo.cellX = c.getInt(cellXIndex);                                          
2167                                  folderInfo.cellY = c.getInt(cellYIndex);                                          
2168                                  folderInfo.spanX = 1;                                                             
2169                                  folderInfo.spanY = 1;                                                             
2170                                                                                                                    
2171                                  // check & update map of what's occupied                                          
2172                                  if (!checkItemPlacement(occupied, folderInfo)) {                                  
2173                                      itemsToRemove.add(id);                                                        
2174                                      break;                                                                        
2175                                  }                                                                                 
2176                                                                                                                    
2177                                  switch (container) {                                                              
2178                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
2179                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
2180                                          sBgWorkspaceItems.add(folderInfo);                                        
2181                                          break;                                                                    
2182                                  }                                                                                 
2183                                                                                                                    
2184                                  if (restored) {                                                                   
2185                                      // no special handling required for restored folders                          
2186                                      restoredRows.add(id);                                                         
2187                                  }                                                                                 
2188                                                                                                                    
2189                                  sBgItemsIdMap.put(folderInfo.id, folderInfo);                                     
2190                                  sBgFolders.put(folderInfo.id, folderInfo);                                        
2191                                  break;                                                                            
2192                                                                                                                    
2193                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
2194                              case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:                           
2195                                  // Read all Launcher-specific widget details                                      
2196                                  boolean customWidget = itemType ==                                                
2197                                      LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;                        
2198                                                                                                                    
2199                                  int appWidgetId = c.getInt(appWidgetIdIndex);                                     
2200                                  String savedProvider = c.getString(appWidgetProviderIndex);                       
2201                                  id = c.getLong(idIndex);                                                          
2202                                  final ComponentName component =                                                   
2203                                          ComponentName.unflattenFromString(savedProvider);                         
2204                                                                                                                    
2205                                  final int restoreStatus = c.getInt(restoredIndex);                                
2206                                  final boolean isIdValid = (restoreStatus &                                        
2207                                          LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) == 0;                            
2208                                                                                                                    
2209                                  final boolean wasProviderReady = (restoreStatus &                                 
2210                                          LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0;                      
2211                                                                                                                    
2212                                  final LauncherAppWidgetProviderInfo provider =                                    
2213                                          LauncherModel.getProviderInfo(context,                                    
2214                                                  ComponentName.unflattenFromString(savedProvider));                
2215                                                                                                                    
2216                                  final boolean isProviderReady = isValidProvider(provider);                        
2217                                  if (!isSafeMode && !customWidget &&                                               
2218                                          wasProviderReady && !isProviderReady) {                                   
2219                                      String log = "Deleting widget that isn't installed anymore: "                 
2220                                              + "id=" + id + " appWidgetId=" + appWidgetId;                         
2221                                                                                                                    
2222                                      Log.e(TAG, log);                                                              
2223                                      Launcher.addDumpLog(TAG, log, false);                                         
2224                                      itemsToRemove.add(id);                                                        
2225                                  } else {                                                                          
2226                                      if (isProviderReady) {                                                        
2227                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2228                                                  provider.provider);                                               
2229                                                                                                                    
2230                                          if (!customWidget) {                                                      
2231                                              int[] minSpan =                                                       
2232                                                      Launcher.getMinSpanForWidget(context, provider);              
2233                                              appWidgetInfo.minSpanX = minSpan[0];                                  
2234                                              appWidgetInfo.minSpanY = minSpan[1];                                  
2235                                          }                                                                         
2236                                                                                                                    
2237                                          int status = restoreStatus;                                               
2238                                          if (!wasProviderReady) {                                                  
2239                                              // If provider was not previously ready, update the                   
2240                                              // status and UI flag.                                                
2241                                                                                                                    
2242                                              // Id would be valid only if the widget restore broadcast was received🔵
2243                                              if (isIdValid) {                                                      
2244                                                  status = LauncherAppWidgetInfo.RESTORE_COMPLETED;                 
2245                                              } else {                                                              
2246                                                  status &= ~LauncherAppWidgetInfo                                  
2247                                                          .FLAG_PROVIDER_NOT_READY;                                 
2248                                              }                                                                     
2249                                          }                                                                         
2250                                          appWidgetInfo.restoreStatus = status;                                     
2251                                      } else {                                                                      
2252                                          Log.v(TAG, "Widget restore pending id=" + id                              
2253                                                  + " appWidgetId=" + appWidgetId                                   
2254                                                  + " status =" + restoreStatus);                                   
2255                                          appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                    
2256                                                  component);                                                       
2257                                          appWidgetInfo.restoreStatus = restoreStatus;                              
2258                                                                                                                    
2259                                          if ((restoreStatus & LauncherAppWidgetInfo.FLAG_RESTORE_STARTED) != 0) {  
2260                                              // Restore has started once.                                          
2261                                          } else if (installingPkgs.contains(component.getPackageName())) {         
2262                                              // App restore has started. Update the flag                           
2263                                              appWidgetInfo.restoreStatus |=                                        
2264                                                      LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;                   
2265                                          } else if (REMOVE_UNRESTORED_ICONS && !isSafeMode) {                      
2266                                              Launcher.addDumpLog(TAG,                                              
2267                                                      "Unrestored widget removed: " + component, true);             
2268                                              itemsToRemove.add(id);                                                
2269                                              continue;                                                             
2270                                          }                                                                         
2271                                      }                                                                             
2272                                                                                                                    
2273                                      appWidgetInfo.id = id;                                                        
2274                                      appWidgetInfo.screenId = c.getInt(screenIndex);                               
2275                                      appWidgetInfo.cellX = c.getInt(cellXIndex);                                   
2276                                      appWidgetInfo.cellY = c.getInt(cellYIndex);                                   
2277                                      appWidgetInfo.spanX = c.getInt(spanXIndex);                                   
2278                                      appWidgetInfo.spanY = c.getInt(spanYIndex);                                   
2279                                                                                                                    
2280                                      if (!customWidget) {                                                          
2281                                          int[] minSpan = Launcher.getMinSpanForWidget(context, provider);          
2282                                          appWidgetInfo.minSpanX = minSpan[0];                                      
2283                                          appWidgetInfo.minSpanY = minSpan[1];                                      
2284                                      }                                                                             
2285                                                                                                                    
2286                                      container = c.getInt(containerIndex);                                         
2287                                      if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&              
2288                                          container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {              
2289                                          Log.e(TAG, "Widget found where container != " +                           
2290                                              "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");               
2291                                          continue;                                                                 
2292                                      }                                                                             
2293                                                                                                                    
2294                                      appWidgetInfo.container = c.getInt(containerIndex);                           
2295                                      // check & update map of what's occupied                                      
2296                                      if (!checkItemPlacement(occupied, appWidgetInfo)) {                           
2297                                          itemsToRemove.add(id);                                                    
2298                                          break;                                                                    
2299                                      }                                                                             
2300                                                                                                                    
2301                                      if (!customWidget) {                                                          
2302                                          String providerName =                                                     
2303                                                  appWidgetInfo.providerName.flattenToString();                     
2304                                          if (!providerName.equals(savedProvider) ||                                
2305                                                  (appWidgetInfo.restoreStatus != restoreStatus)) {                 
2306                                              ContentValues values = new ContentValues();                           
2307                                              values.put(                                                           
2308                                                      LauncherSettings.Favorites.APPWIDGET_PROVIDER,                
2309                                                      providerName);                                                
2310                                              values.put(LauncherSettings.Favorites.RESTORED,                       
2311                                                      appWidgetInfo.restoreStatus);                                 
2312                                              updateItem(id, values);                                               
2313                                          }                                                                         
2314                                      }                                                                             
2315                                      sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                           
2316                                      sBgAppWidgets.add(appWidgetInfo);                                             
2317                                  }                                                                                 
2318                                  break;                                                                            
2319                              }                                                                                     
2320                          } catch (Exception e) {                                                                   
2321                              Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);               
2322                          }                                                                                         
2323                      }                                                                                             
2324                  } finally {                                                                                       
2325                      if (c != null) {                                                                              
2326                          c.close();                                                                                
2327                      }                                                                                             
2328                  }                                                                                                 
2329                                                                                                                    
2330                  // Break early if we've stopped loading                                                           
2331                  if (mStopped) {                                                                                   
2332                      clearSBgDataStructures();                                                                     
2333                      return;                                                                                       
2334                  }                                                                                                 
2335                                                                                                                    
2336                  if (itemsToRemove.size() > 0) {                                                                   
2337                      ContentProviderClient client = contentResolver.acquireContentProviderClient(                  
2338                              contentUri);                                                                          
2339                      // Remove dead items                                                                          
2340                      for (long id : itemsToRemove) {                                                               
2341                          if (DEBUG_LOADERS) {                                                                      
2342                              Log.d(TAG, "Removed id = " + id);                                                     
2343                          }                                                                                         
2344                          // Don't notify content observers                                                         
2345                          try {                                                                                     
2346                              client.delete(LauncherSettings.Favorites.getContentUri(id, false),                    
2347                                      null, null);                                                                  
2348                          } catch (RemoteException e) {                                                             
2349                              Log.w(TAG, "Could not remove id = " + id);                                            
2350                          }                                                                                         
2351                      }                                                                                             
2352                  }                                                                                                 
2353                                                                                                                    
2354                  if (restoredRows.size() > 0) {                                                                    
2355                      ContentProviderClient updater = contentResolver.acquireContentProviderClient(                 
2356                              contentUri);                                                                          
2357                      // Update restored items that no longer require special handling                              
2358                      try {                                                                                         
2359                          StringBuilder selectionBuilder = new StringBuilder();                                     
2360                          selectionBuilder.append(LauncherSettings.Favorites._ID);                                  
2361                          selectionBuilder.append(" IN (");                                                         
2362                          selectionBuilder.append(TextUtils.join(", ", restoredRows));                              
2363                          selectionBuilder.append(")");                                                             
2364                          ContentValues values = new ContentValues();                                               
2365                          values.put(LauncherSettings.Favorites.RESTORED, 0);                                       
2366                          updater.update(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                    
2367                                  values, selectionBuilder.toString(), null);                                       
2368                      } catch (RemoteException e) {                                                                 
2369                          Log.w(TAG, "Could not update restored rows");                                             
2370                      }                                                                                             
2371                  }                                                                                                 
2372                                                                                                                    
2373                  if (!isSdCardReady && !sPendingPackages.isEmpty()) {                                              
2374                      context.registerReceiver(new AppsAvailabilityCheck(),                                         
2375                              new IntentFilter(StartupReceiver.SYSTEM_READY),                                       
2376                              null, sWorker);                                                                       
2377                  }                                                                                                 
2378                                                                                                                    
2379                  sBgWorkspaceScreens.addAll(loadWorkspaceScreensDb(mContext));                                     
2380                  // Log to disk                                                                                    
2381                  Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                                   
2382                          TextUtils.join(", ", sBgWorkspaceScreens), true);                                         
2383                                                                                                                    
2384                  // Remove any empty screens                                                                       
2385                  ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                         
2386                  for (ItemInfo item: sBgItemsIdMap.values()) {                                                     
2387                      long screenId = item.screenId;                                                                
2388                      if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                         
2389                              unusedScreens.contains(screenId)) {                                                   
2390                          unusedScreens.remove(screenId);                                                           
2391                      }                                                                                             
2392                  }                                                                                                 
2393                                                                                                                    
2394                  // If there are any empty screens remove them, and update.                                        
2395                  if (unusedScreens.size() != 0) {                                                                  
2396                      // Log to disk                                                                                
2397                      Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +                     
2398                              TextUtils.join(", ", unusedScreens), true);                                           
2399                                                                                                                    
2400                      sBgWorkspaceScreens.removeAll(unusedScreens);                                                 
2401                      updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                     
2402                  }                                                                                                 
2403                                                                                                                    
2404                  if (DEBUG_LOADERS) {                                                                              
2405                      Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");                   
2406                      Log.d(TAG, "workspace layout: ");                                                             
2407                      int nScreens = occupied.size();                                                               
2408                      for (int y = 0; y < countY; y++) {                                                            
2409                          String line = "";                                                                         
2410                                                                                                                    
2411                          Iterator<Long> iter = occupied.keySet().iterator();                                       
2412                          while (iter.hasNext()) {                                                                  
2413                              long screenId = iter.next();                                                          
2414                              if (screenId > 0) {                                                                   
2415                                  line += " | ";                                                                    
2416                              }                                                                                     
2417                              for (int x = 0; x < countX; x++) {                                                    
2418                                  ItemInfo[][] screen = occupied.get(screenId);                                     
2419                                  if (x < screen.length && y < screen[x].length) {                                  
2420                                      line += (screen[x][y] != null) ? "#" : ".";                                   
2421                                  } else {                                                                          
2422                                      line += "!";                                                                  
2423                                  }                                                                                 
2424                              }                                                                                     
2425                          }                                                                                         
2426                          Log.d(TAG, "[ " + line + " ]");                                                           
2427                      }                                                                                             
2428                  }                                                                                                 
2429              }                                                                                                     
2430          }                                                                                                         
2431                                                                                                                    
2432          /**                                                                                                       
2433           * Partially updates the item without any notification. Must be called on the worker thread.              
2434           */                                                                                                       
2435          private void updateItem(long itemId, ContentValues update) {                                              
2436              mContext.getContentResolver().update(                                                                 
2437                      LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                       
2438                      update,                                                                                       
2439                      BaseColumns._ID + "= ?",                                                                      
2440                      new String[]{Long.toString(itemId)});                                                         
2441          }                                                                                                         
2442                                                                                                                    
2443          /** Filters the set of items who are directly or indirectly (via another container) on the                
2444           * specified screen. */                                                                                   
2445          private void filterCurrentWorkspaceItems(long currentScreenId,                                            
2446                  ArrayList<ItemInfo> allWorkspaceItems,                                                            
2447                  ArrayList<ItemInfo> currentScreenItems,                                                           
2448                  ArrayList<ItemInfo> otherScreenItems) {                                                           
2449              // Purge any null ItemInfos                                                                           
2450              Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                               
2451              while (iter.hasNext()) {                                                                              
2452                  ItemInfo i = iter.next();                                                                         
2453                  if (i == null) {                                                                                  
2454                      iter.remove();                                                                                
2455                  }                                                                                                 
2456              }                                                                                                     
2457                                                                                                                    
2458              // Order the set of items by their containers first, this allows use to walk through the              
2459              // list sequentially, build up a list of containers that are in the specified screen,                 
2460              // as well as all items in those containers.                                                          
2461              Set<Long> itemsOnScreen = new HashSet<Long>();                                                        
2462              Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                                      
2463                  @Override                                                                                         
2464                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2465                      return (int) (lhs.container - rhs.container);                                                 
2466                  }                                                                                                 
2467              });                                                                                                   
2468              for (ItemInfo info : allWorkspaceItems) {                                                             
2469                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
2470                      if (info.screenId == currentScreenId) {                                                       
2471                          currentScreenItems.add(info);                                                             
2472                          itemsOnScreen.add(info.id);                                                               
2473                      } else {                                                                                      
2474                          otherScreenItems.add(info);                                                               
2475                      }                                                                                             
2476                  } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                      
2477                      currentScreenItems.add(info);                                                                 
2478                      itemsOnScreen.add(info.id);                                                                   
2479                  } else {                                                                                          
2480                      if (itemsOnScreen.contains(info.container)) {                                                 
2481                          currentScreenItems.add(info);                                                             
2482                          itemsOnScreen.add(info.id);                                                               
2483                      } else {                                                                                      
2484                          otherScreenItems.add(info);                                                               
2485                      }                                                                                             
2486                  }                                                                                                 
2487              }                                                                                                     
2488          }                                                                                                         
2489                                                                                                                    
2490          /** Filters the set of widgets which are on the specified screen. */                                      
2491          private void filterCurrentAppWidgets(long currentScreenId,                                                
2492                  ArrayList<LauncherAppWidgetInfo> appWidgets,                                                      
2493                  ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                            
2494                  ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                            
2495                                                                                                                    
2496              for (LauncherAppWidgetInfo widget : appWidgets) {                                                     
2497                  if (widget == null) continue;                                                                     
2498                  if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                           
2499                          widget.screenId == currentScreenId) {                                                     
2500                      currentScreenWidgets.add(widget);                                                             
2501                  } else {                                                                                          
2502                      otherScreenWidgets.add(widget);                                                               
2503                  }                                                                                                 
2504              }                                                                                                     
2505          }                                                                                                         
2506                                                                                                                    
2507          /** Filters the set of folders which are on the specified screen. */                                      
2508          private void filterCurrentFolders(long currentScreenId,                                                   
2509                  HashMap<Long, ItemInfo> itemsIdMap,                                                               
2510                  HashMap<Long, FolderInfo> folders,                                                                
2511                  HashMap<Long, FolderInfo> currentScreenFolders,                                                   
2512                  HashMap<Long, FolderInfo> otherScreenFolders) {                                                   
2513                                                                                                                    
2514              for (long id : folders.keySet()) {                                                                    
2515                  ItemInfo info = itemsIdMap.get(id);                                                               
2516                  FolderInfo folder = folders.get(id);                                                              
2517                  if (info == null || folder == null) continue;                                                     
2518                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                             
2519                          info.screenId == currentScreenId) {                                                       
2520                      currentScreenFolders.put(id, folder);                                                         
2521                  } else {                                                                                          
2522                      otherScreenFolders.put(id, folder);                                                           
2523                  }                                                                                                 
2524              }                                                                                                     
2525          }                                                                                                         
2526                                                                                                                    
2527          /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to                   
2528           * right) */                                                                                              
2529          private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                            
2530              final LauncherAppState app = LauncherAppState.getInstance();                                          
2531              final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                   
2532              // XXX: review this                                                                                   
2533              Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                         
2534                  @Override                                                                                         
2535                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2536                      int cellCountX = (int) grid.numColumns;                                                       
2537                      int cellCountY = (int) grid.numRows;                                                          
2538                      int screenOffset = cellCountX * cellCountY;                                                   
2539                      int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat               
2540                      long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +                    
2541                              lhs.cellY * cellCountX + lhs.cellX);                                                  
2542                      long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +                    
2543                              rhs.cellY * cellCountX + rhs.cellX);                                                  
2544                      return (int) (lr - rr);                                                                       
2545                  }                                                                                                 
2546              });                                                                                                   
2547          }                                                                                                         
2548                                                                                                                    
2549          private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                           
2550                  final ArrayList<Long> orderedScreens) {                                                           
2551              final Runnable r = new Runnable() {                                                                   
2552                  @Override                                                                                         
2553                  public void run() {                                                                               
2554                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2555                      if (callbacks != null) {                                                                      
2556                          callbacks.bindScreens(orderedScreens);                                                    
2557                      }                                                                                             
2558                  }                                                                                                 
2559              };                                                                                                    
2560              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2561          }                                                                                                         
2562                                                                                                                    
2563          private void bindWorkspaceItems(final Callbacks oldCallbacks,                                             
2564                  final ArrayList<ItemInfo> workspaceItems,                                                         
2565                  final ArrayList<LauncherAppWidgetInfo> appWidgets,                                                
2566                  final HashMap<Long, FolderInfo> folders,                                                          
2567                  ArrayList<Runnable> deferredBindRunnables) {                                                      
2568                                                                                                                    
2569              final boolean postOnMainThread = (deferredBindRunnables != null);                                     
2570                                                                                                                    
2571              // Bind the workspace items                                                                           
2572              int N = workspaceItems.size();                                                                        
2573              for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                            
2574                  final int start = i;                                                                              
2575                  final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                                 
2576                  final Runnable r = new Runnable() {                                                               
2577                      @Override                                                                                     
2578                      public void run() {                                                                           
2579                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2580                          if (callbacks != null) {                                                                  
2581                              callbacks.bindItems(workspaceItems, start, start+chunkSize,                           
2582                                      false);                                                                       
2583                          }                                                                                         
2584                      }                                                                                             
2585                  };                                                                                                
2586                  if (postOnMainThread) {                                                                           
2587                      synchronized (deferredBindRunnables) {                                                        
2588                          deferredBindRunnables.add(r);                                                             
2589                      }                                                                                             
2590                  } else {                                                                                          
2591                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2592                  }                                                                                                 
2593              }                                                                                                     
2594                                                                                                                    
2595              // Bind the folders                                                                                   
2596              if (!folders.isEmpty()) {                                                                             
2597                  final Runnable r = new Runnable() {                                                               
2598                      public void run() {                                                                           
2599                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2600                          if (callbacks != null) {                                                                  
2601                              callbacks.bindFolders(folders);                                                       
2602                          }                                                                                         
2603                      }                                                                                             
2604                  };                                                                                                
2605                  if (postOnMainThread) {                                                                           
2606                      synchronized (deferredBindRunnables) {                                                        
2607                          deferredBindRunnables.add(r);                                                             
2608                      }                                                                                             
2609                  } else {                                                                                          
2610                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2611                  }                                                                                                 
2612              }                                                                                                     
2613                                                                                                                    
2614              // Bind the widgets, one at a time                                                                    
2615              N = appWidgets.size();                                                                                
2616              for (int i = 0; i < N; i++) {                                                                         
2617                  final LauncherAppWidgetInfo widget = appWidgets.get(i);                                           
2618                  final Runnable r = new Runnable() {                                                               
2619                      public void run() {                                                                           
2620                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2621                          if (callbacks != null) {                                                                  
2622                              callbacks.bindAppWidget(widget);                                                      
2623                          }                                                                                         
2624                      }                                                                                             
2625                  };                                                                                                
2626                  if (postOnMainThread) {                                                                           
2627                      deferredBindRunnables.add(r);                                                                 
2628                  } else {                                                                                          
2629                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2630                  }                                                                                                 
2631              }                                                                                                     
2632          }                                                                                                         
2633                                                                                                                    
2634          /**                                                                                                       
2635           * Binds all loaded data to actual views on the main thread.                                              
2636           */                                                                                                       
2637          private void bindWorkspace(int synchronizeBindPage) {                                                     
2638              final long t = SystemClock.uptimeMillis();                                                            
2639              Runnable r;                                                                                           
2640                                                                                                                    
2641              // Don't use these two variables in any of the callback runnables.                                    
2642              // Otherwise we hold a reference to them.                                                             
2643              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2644              if (oldCallbacks == null) {                                                                           
2645                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2646                  Log.w(TAG, "LoaderTask running with no launcher");                                                
2647                  return;                                                                                           
2648              }                                                                                                     
2649                                                                                                                    
2650              // Save a copy of all the bg-thread collections                                                       
2651              ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                                       
2652              ArrayList<LauncherAppWidgetInfo> appWidgets =                                                         
2653                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2654              HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                                  
2655              HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                                   
2656              ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                             
2657              synchronized (sBgLock) {                                                                              
2658                  workspaceItems.addAll(sBgWorkspaceItems);                                                         
2659                  appWidgets.addAll(sBgAppWidgets);                                                                 
2660                  folders.putAll(sBgFolders);                                                                       
2661                  itemsIdMap.putAll(sBgItemsIdMap);                                                                 
2662                  orderedScreenIds.addAll(sBgWorkspaceScreens);                                                     
2663              }                                                                                                     
2664                                                                                                                    
2665              final boolean isLoadingSynchronously =                                                                
2666                      synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                                        
2667              int currScreen = isLoadingSynchronously ? synchronizeBindPage :                                       
2668                  oldCallbacks.getCurrentWorkspaceScreen();                                                         
2669              if (currScreen >= orderedScreenIds.size()) {                                                          
2670                  // There may be no workspace screens (just hotseat items and an empty page).                      
2671                  currScreen = PagedView.INVALID_RESTORE_PAGE;                                                      
2672              }                                                                                                     
2673              final int currentScreen = currScreen;                                                                 
2674              final long currentScreenId = currentScreen < 0                                                        
2675                      ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                                    
2676                                                                                                                    
2677              // Load all the items that are on the current page first (and in the process, unbind                  
2678              // all the existing workspace items before we call startBinding() below.                              
2679              unbindWorkspaceItemsOnMainThread();                                                                   
2680                                                                                                                    
2681              // Separate the items that are on the current screen, and all the other remaining items               
2682              ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                                
2683              ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                                  
2684              ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                                  
2685                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2686              ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                                    
2687                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2688              HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                           
2689              HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                             
2690                                                                                                                    
2691              filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,                   
2692                      otherWorkspaceItems);                                                                         
2693              filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                               
2694                      otherAppWidgets);                                                                             
2695              filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                            
2696                      otherFolders);                                                                                
2697              sortWorkspaceItemsSpatially(currentWorkspaceItems);                                                   
2698              sortWorkspaceItemsSpatially(otherWorkspaceItems);                                                     
2699                                                                                                                    
2700              // Tell the workspace that we're about to start binding items                                         
2701              r = new Runnable() {                                                                                  
2702                  public void run() {                                                                               
2703                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2704                      if (callbacks != null) {                                                                      
2705                          callbacks.startBinding();                                                                 
2706                      }                                                                                             
2707                  }                                                                                                 
2708              };                                                                                                    
2709              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2710                                                                                                                    
2711              bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                                 
2712                                                                                                                    
2713              // Load items on the current page                                                                     
2714              bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                            
2715                      currentFolders, null);                                                                        
2716              if (isLoadingSynchronously) {                                                                         
2717                  r = new Runnable() {                                                                              
2718                      public void run() {                                                                           
2719                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2720                          if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {               
2721                              callbacks.onPageBoundSynchronously(currentScreen);                                    
2722                          }                                                                                         
2723                      }                                                                                             
2724                  };                                                                                                
2725                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2726              }                                                                                                     
2727                                                                                                                    
2728              // Load all the remaining pages (if we are loading synchronously, we want to defer this               
2729              // work until after the first render)                                                                 
2730              synchronized (mDeferredBindRunnables) {                                                               
2731                  mDeferredBindRunnables.clear();                                                                   
2732              }                                                                                                     
2733              bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                  
2734                      (isLoadingSynchronously ? mDeferredBindRunnables : null));                                    
2735                                                                                                                    
2736              // Tell the workspace that we're done binding items                                                   
2737              r = new Runnable() {                                                                                  
2738                  public void run() {                                                                               
2739                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2740                      if (callbacks != null) {                                                                      
2741                          callbacks.finishBindingItems();                                                           
2742                      }                                                                                             
2743                                                                                                                    
2744                      // If we're profiling, ensure this is the last thing in the queue.                            
2745                      if (DEBUG_LOADERS) {                                                                          
2746                          Log.d(TAG, "bound workspace in "                                                          
2747                              + (SystemClock.uptimeMillis()-t) + "ms");                                             
2748                      }                                                                                             
2749                                                                                                                    
2750                      mIsLoadingAndBindingWorkspace = false;                                                        
2751                  }                                                                                                 
2752              };                                                                                                    
2753              if (isLoadingSynchronously) {                                                                         
2754                  synchronized (mDeferredBindRunnables) {                                                           
2755                      mDeferredBindRunnables.add(r);                                                                
2756                  }                                                                                                 
2757              } else {                                                                                              
2758                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2759              }                                                                                                     
2760          }                                                                                                         
2761                                                                                                                    
2762          private void loadAndBindAllApps() {                                                                       
2763              if (DEBUG_LOADERS) {                                                                                  
2764                  Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                                
2765              }                                                                                                     
2766              if (!mAllAppsLoaded) {                                                                                
2767                  loadAllApps();                                                                                    
2768                  synchronized (LoaderTask.this) {                                                                  
2769                      if (mStopped) {                                                                               
2770                          return;                                                                                   
2771                      }                                                                                             
2772                      mAllAppsLoaded = true;                                                                        
2773                  }                                                                                                 
2774              } else {                                                                                              
2775                  onlyBindAllApps();                                                                                
2776              }                                                                                                     
2777          }                                                                                                         
2778                                                                                                                    
2779          private void onlyBindAllApps() {                                                                          
2780              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2781              if (oldCallbacks == null) {                                                                           
2782                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2783                  Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                              
2784                  return;                                                                                           
2785              }                                                                                                     
2786                                                                                                                    
2787              // shallow copy                                                                                       
2788              @SuppressWarnings("unchecked")                                                                        
2789              final ArrayList<AppInfo> list                                                                         
2790                      = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                           
2791              Runnable r = new Runnable() {                                                                         
2792                  public void run() {                                                                               
2793                      final long t = SystemClock.uptimeMillis();                                                    
2794                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2795                      if (callbacks != null) {                                                                      
2796                          callbacks.bindAllApplications(list);                                                      
2797                      }                                                                                             
2798                      if (DEBUG_LOADERS) {                                                                          
2799                          Log.d(TAG, "bound all " + list.size() + " apps from cache in "                            
2800                                  + (SystemClock.uptimeMillis()-t) + "ms");                                         
2801                      }                                                                                             
2802                  }                                                                                                 
2803              };                                                                                                    
2804              boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());                    
2805              if (isRunningOnMainThread) {                                                                          
2806                  r.run();                                                                                          
2807              } else {                                                                                              
2808                  mHandler.post(r);                                                                                 
2809              }                                                                                                     
2810          }                                                                                                         
2811                                                                                                                    
2812          private void loadAllApps() {                                                                              
2813              final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2814                                                                                                                    
2815              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2816              if (oldCallbacks == null) {                                                                           
2817                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2818                  Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                                  
2819                  return;                                                                                           
2820              }                                                                                                     
2821                                                                                                                    
2822              final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                                       
2823              mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                     
2824                                                                                                                    
2825              final List<UserHandleCompat> profiles = mUserManager.getUserProfiles();                               
2826                                                                                                                    
2827              // Clear the list of apps                                                                             
2828              mBgAllAppsList.clear();                                                                               
2829              SharedPreferences prefs = mContext.getSharedPreferences(                                              
2830                      LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                            
2831              for (UserHandleCompat user : profiles) {                                                              
2832                  // Query for the set of apps                                                                      
2833                  final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                              
2834                  List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);                
2835                  if (DEBUG_LOADERS) {                                                                              
2836                      Log.d(TAG, "getActivityList took "                                                            
2837                              + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);                      
2838                      Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);                  
2839                  }                                                                                                 
2840                  // Fail if we don't have any apps                                                                 
2841                  // TODO: Fix this. Only fail for the current user.                                                
2842                  if (apps == null || apps.isEmpty()) {                                                             
2843                      return;                                                                                       
2844                  }                                                                                                 
2845                  // Sort the applications by name                                                                  
2846                  final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                             
2847                  Collections.sort(apps,                                                                            
2848                          new LauncherModel.ShortcutNameComparator(mLabelCache));                                   
2849                  if (DEBUG_LOADERS) {                                                                              
2850                      Log.d(TAG, "sort took "                                                                       
2851                              + (SystemClock.uptimeMillis()-sortTime) + "ms");                                      



































2852                  }                                                                                                 
2853                                                                                                                    
2854                  // Create the ApplicationInfos                                                                    
2855                  for (int i = 0; i < apps.size(); i++) {                                                           
2856                      LauncherActivityInfoCompat app = apps.get(i);                                                 
2857                      // This builds the icon bitmaps.                                                              
2858                      mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, mLabelCache));                

2859                  }                                                                                                 
2860                                                                                                                    
2861                  if (ADD_MANAGED_PROFILE_SHORTCUTS && !user.equals(UserHandleCompat.myUserHandle())) {             
2862                      // Add shortcuts for packages which were installed while launcher was dead.                   
2863                      String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                       
2864                              + mUserManager.getSerialNumberForUser(user);                                          
2865                      Set<String> packagesAdded = prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET);       
2866                      HashSet<String> newPackageSet = new HashSet<String>();                                        
2867                                                                                                                    
2868                      for (LauncherActivityInfoCompat info : apps) {                                                
2869                          String packageName = info.getComponentName().getPackageName();                            
2870                          if (!packagesAdded.contains(packageName)                                                  
2871                                  && !newPackageSet.contains(packageName)) {                                        
2872                              InstallShortcutReceiver.queueInstallShortcut(info, mContext);                         
2873                          }                                                                                         
2874                          newPackageSet.add(packageName);                                                           
2875                      }                                                                                             
2876                                                                                                                    
2877                      prefs.edit().putStringSet(shortcutsSetKey, newPackageSet).commit();                           
2878                  }                                                                                                 
2879              }                                                                                                     
2880              // Huh? Shouldn't this be inside the Runnable below?                                                  
2881              final ArrayList<AppInfo> added = mBgAllAppsList.added;                                                
2882              mBgAllAppsList.added = new ArrayList<AppInfo>();                                                      
2883                                                                                                                    
2884              // Post callback on main thread                                                                       
2885              mHandler.post(new Runnable() {                                                                        
2886                  public void run() {                                                                               
2887                      final long bindTime = SystemClock.uptimeMillis();                                             
2888                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2889                      if (callbacks != null) {                                                                      
2890                          callbacks.bindAllApplications(added);                                                     
2891                          if (DEBUG_LOADERS) {                                                                      
2892                              Log.d(TAG, "bound " + added.size() + " apps in "                                      
2893                                  + (SystemClock.uptimeMillis() - bindTime) + "ms");                                
2894                          }                                                                                         
2895                      } else {                                                                                      
2896                          Log.i(TAG, "not binding apps: no Launcher activity");                                     
2897                      }                                                                                             
2898                  }                                                                                                 
2899              });                                                                                                   
2900                                                                                                                    
2901              if (DEBUG_LOADERS) {                                                                                  
2902                  Log.d(TAG, "Icons processed in "                                                                  
2903                          + (SystemClock.uptimeMillis() - loadTime) + "ms");                                        
2904              }                                                                                                     
2905          }                                                                                                         
2906                                                                                                                    
2907          public void dumpState() {                                                                                 
2908              synchronized (sBgLock) {                                                                              
2909                  Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                                   
2910                  Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                           
2911                  Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                                   
2912                  Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);                   
2913                  Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                            
2914              }                                                                                                     
2915          }                                                                                                         
2916      }                                                                                                             
2917                                                                                                                    
2918      void enqueuePackageUpdated(PackageUpdatedTask task) {                                                         
2919          sWorker.post(task);                                                                                       
2920      }                                                                                                             
2921                                                                                                                    
2922      private class AppsAvailabilityCheck extends BroadcastReceiver {                                               
2923                                                                                                                    
2924          @Override                                                                                                 
2925          public void onReceive(Context context, Intent intent) {                                                   
2926              synchronized (sBgLock) {                                                                              
2927                  final LauncherAppsCompat launcherApps = LauncherAppsCompat                                        
2928                          .getInstance(mApp.getContext());                                                          
2929                  final PackageManager manager = context.getPackageManager();                                       
2930                  final ArrayList<String> packagesRemoved = new ArrayList<String>();                                
2931                  final ArrayList<String> packagesUnavailable = new ArrayList<String>();                            
2932                  for (Entry<UserHandleCompat, HashSet<String>> entry : sPendingPackages.entrySet()) {              
2933                      UserHandleCompat user = entry.getKey();                                                       
2934                      packagesRemoved.clear();                                                                      
2935                      packagesUnavailable.clear();                                                                  
2936                      for (String pkg : entry.getValue()) {                                                         
2937                          if (!launcherApps.isPackageEnabledForProfile(pkg, user)) {                                
2938                              boolean packageOnSdcard = launcherApps.isAppEnabled(                                  
2939                                      manager, pkg, PackageManager.GET_UNINSTALLED_PACKAGES);                       
2940                              if (packageOnSdcard) {                                                                
2941                                  Launcher.addDumpLog(TAG, "Package found on sd-card: " + pkg, true);               
2942                                  packagesUnavailable.add(pkg);                                                     
2943                              } else {                                                                              
2944                                  Launcher.addDumpLog(TAG, "Package not found: " + pkg, true);                      
2945                                  packagesRemoved.add(pkg);                                                         
2946                              }                                                                                     
2947                          }                                                                                         
2948                      }                                                                                             
2949                      if (!packagesRemoved.isEmpty()) {                                                             
2950                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_REMOVE,                
2951                                  packagesRemoved.toArray(new String[packagesRemoved.size()]), user));              
2952                      }                                                                                             
2953                      if (!packagesUnavailable.isEmpty()) {                                                         
2954                          enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UNAVAILABLE,           
2955                                  packagesUnavailable.toArray(new String[packagesUnavailable.size()]), user));      
2956                      }                                                                                             
2957                  }                                                                                                 
2958                  sPendingPackages.clear();                                                                         
2959              }                                                                                                     
2960          }                                                                                                         
2961      }                                                                                                             
2962                                                                                                                    
2963      private class PackageUpdatedTask implements Runnable {                                                        
2964          int mOp;                                                                                                  
2965          String[] mPackages;                                                                                       
2966          UserHandleCompat mUser;                                                                                   
2967                                                                                                                    
2968          public static final int OP_NONE = 0;                                                                      
2969          public static final int OP_ADD = 1;                                                                       
2970          public static final int OP_UPDATE = 2;                                                                    
2971          public static final int OP_REMOVE = 3; // uninstlled                                                      
2972          public static final int OP_UNAVAILABLE = 4; // external media unmounted                                   
2973                                                                                                                    
2974                                                                                                                    
2975          public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {                             
2976              mOp = op;                                                                                             
2977              mPackages = packages;                                                                                 
2978              mUser = user;                                                                                         
2979          }                                                                                                         
2980                                                                                                                    
2981          public void run() {                                                                                       
2982              final Context context = mApp.getContext();                                                            
2983                                                                                                                    
2984              final String[] packages = mPackages;                                                                  
2985              final int N = packages.length;                                                                        
2986              switch (mOp) {                                                                                        
2987                  case OP_ADD:                                                                                      
2988                      for (int i=0; i<N; i++) {                                                                     
2989                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                  
2990                          mIconCache.remove(packages[i], mUser);                                                    

2991                          mBgAllAppsList.addPackage(context, packages[i], mUser);                                   
2992                      }                                                                                             
2993                                                                                                                    
2994                      // Auto add shortcuts for added packages.                                                     
2995                      if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
2996                              && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
2997                          SharedPreferences prefs = context.getSharedPreferences(                                   
2998                                  LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
2999                          String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3000                                  + mUserManager.getSerialNumberForUser(mUser);                                     
3001                          Set<String> shortcutSet = new HashSet<String>(                                            
3002                                  prefs.getStringSet(shortcutsSetKey,Collections.EMPTY_SET));                       
3003                                                                                                                    
3004                          for (int i=0; i<N; i++) {                                                                 
3005                              if (!shortcutSet.contains(packages[i])) {                                             
3006                                  shortcutSet.add(packages[i]);                                                     
3007                                  List<LauncherActivityInfoCompat> activities =                                     
3008                                          mLauncherApps.getActivityList(packages[i], mUser);                        
3009                                  if (activities != null && !activities.isEmpty()) {                                
3010                                      InstallShortcutReceiver.queueInstallShortcut(                                 
3011                                              activities.get(0), context);                                          
3012                                  }                                                                                 
3013                              }                                                                                     
3014                          }                                                                                         
3015                                                                                                                    
3016                          prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3017                      }                                                                                             
3018                      break;                                                                                        
3019                  case OP_UPDATE:                                                                                   
3020                      for (int i=0; i<N; i++) {                                                                     
3021                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);               

3022                          mBgAllAppsList.updatePackage(context, packages[i], mUser);                                
3023                          WidgetPreviewLoader.removePackageFromDb(                                                  
3024                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
3025                      }                                                                                             
3026                      break;                                                                                        
3027                  case OP_REMOVE:                                                                                   
3028                      // Remove the packageName for the set of auto-installed shortcuts. This                       
3029                      // will ensure that the shortcut when the app is installed again.                             
3030                      if (ADD_MANAGED_PROFILE_SHORTCUTS                                                             
3031                              && !UserHandleCompat.myUserHandle().equals(mUser)) {                                  
3032                          SharedPreferences prefs = context.getSharedPreferences(                                   
3033                                  LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);                
3034                          String shortcutsSetKey = INSTALLED_SHORTCUTS_SET_PREFIX                                   
3035                                  + mUserManager.getSerialNumberForUser(mUser);                                     
3036                          HashSet<String> shortcutSet = new HashSet<String>(                                        
3037                                  prefs.getStringSet(shortcutsSetKey, Collections.EMPTY_SET));                      
3038                          shortcutSet.removeAll(Arrays.asList(mPackages));                                          
3039                          prefs.edit().putStringSet(shortcutsSetKey, shortcutSet).commit();                         
3040                      }                                                                                             




3041                      // Fall through                                                                               
3042                  case OP_UNAVAILABLE:                                                                              
3043                      boolean clearCache = mOp == OP_REMOVE;                                                        
3044                      for (int i=0; i<N; i++) {                                                                     
3045                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
3046                          mBgAllAppsList.removePackage(packages[i], mUser, clearCache);                             

3047                          WidgetPreviewLoader.removePackageFromDb(                                                  
3048                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
3049                      }                                                                                             
3050                      break;                                                                                        
3051              }                                                                                                     
3052                                                                                                                    
3053              ArrayList<AppInfo> added = null;                                                                      
3054              ArrayList<AppInfo> modified = null;                                                                   
3055              final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                                      
3056                                                                                                                    
3057              if (mBgAllAppsList.added.size() > 0) {                                                                
3058                  added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                             
3059                  mBgAllAppsList.added.clear();                                                                     
3060              }                                                                                                     
3061              if (mBgAllAppsList.modified.size() > 0) {                                                             
3062                  modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                                       
3063                  mBgAllAppsList.modified.clear();                                                                  
3064              }                                                                                                     
3065              if (mBgAllAppsList.removed.size() > 0) {                                                              
3066                  removedApps.addAll(mBgAllAppsList.removed);                                                       
3067                  mBgAllAppsList.removed.clear();                                                                   
3068              }                                                                                                     
3069                                                                                                                    
3070              final Callbacks callbacks = getCallback();                                                            
3071              if (callbacks == null) {                                                                              
3072                  Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");                   
3073                  return;                                                                                           
3074              }                                                                                                     
3075                                                                                                                    
3076              final HashMap<ComponentName, AppInfo> addedOrUpdatedApps =                                            
3077                      new HashMap<ComponentName, AppInfo>();                                                        
3078                                                                                                                    
3079              if (added != null) {                                                                                  
3080 -                // Ensure that we add all the workspace applications to the db                                    
3081 -                if (LauncherAppState.isDisableAllApps()) {                                                        
3082 -                    final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);                        
3083 -                    addAndBindAddedWorkspaceApps(context, addedInfos);                                            
3084 -                } else {                                                                                          
3085 -                    addAppsToAllApps(context, added);                                                             
3086 -                }                                                                                                 
3087 +                addAppsToAllApps(context, added);                                                                 
3088                  for (AppInfo ai : added) {                                                                        
3089                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3090                  }                                                                                                 
3091              }                                                                                                     
3092                                                                                                                    
3093              if (modified != null) {                                                                               
3094                  final ArrayList<AppInfo> modifiedFinal = modified;                                                
3095                  for (AppInfo ai : modified) {                                                                     
3096                      addedOrUpdatedApps.put(ai.componentName, ai);                                                 
3097                  }                                                                                                 
3098                                                                                                                    
3099                  mHandler.post(new Runnable() {                                                                    
3100                      public void run() {                                                                           
3101                          Callbacks cb = getCallback();                                                             
3102                          if (callbacks == cb && cb != null) {                                                      
3103                              callbacks.bindAppsUpdated(modifiedFinal);                                             
3104                          }                                                                                         
3105                      }                                                                                             
3106                  });                                                                                               
3107              }                                                                                                     
3108                                                                                                                    
3109              // Update shortcut infos                                                                              
3110              if (mOp == OP_ADD || mOp == OP_UPDATE) {                                                              
3111                  final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();                   
3112                  final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();                   
3113                  final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();          
3114                                                                                                                    
3115                  HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));                        
3116                  synchronized (sBgLock) {                                                                          
3117                      for (ItemInfo info : sBgItemsIdMap.values()) {                                                
3118                          if (info instanceof ShortcutInfo && mUser.equals(info.user)) {                            
3119                              ShortcutInfo si = (ShortcutInfo) info;                                                
3120                              boolean infoUpdated = false;                                                          
3121                              boolean shortcutUpdated = false;                                                      
3122                                                                                                                    
3123                              // Update shortcuts which use iconResource.                                           
3124                              if ((si.iconResource != null)                                                         
3125                                      && packageSet.contains(si.iconResource.packageName)) {                        
3126                                  Bitmap icon = Utilities.createIconBitmap(si.iconResource.packageName,             
3127                                          si.iconResource.resourceName, mIconCache, context);                       
3128                                  if (icon != null) {                                                               
3129                                      si.setIcon(icon);                                                             
3130                                      si.usingFallbackIcon = false;                                                 
3131                                      infoUpdated = true;                                                           
3132                                  }                                                                                 
3133                              }                                                                                     
3134                                                                                                                    
3135                              ComponentName cn = si.getTargetComponent();                                           
3136                              if (cn != null && packageSet.contains(cn.getPackageName())) {                         
3137                                  AppInfo appInfo = addedOrUpdatedApps.get(cn);                                     
3138                                                                                                                    
3139                                  if (si.isPromise()) {                                                             
3140                                      mIconCache.deletePreloadedIcon(cn, mUser);                                    
3141                                      if (si.hasStatusFlag(ShortcutInfo.FLAG_AUTOINTALL_ICON)) {                    
3142                                          // Auto install icon                                                      
3143                                          PackageManager pm = context.getPackageManager();                          
3144                                          ResolveInfo matched = pm.resolveActivity(                                 
3145                                                  new Intent(Intent.ACTION_MAIN)                                    
3146                                                  .setComponent(cn).addCategory(Intent.CATEGORY_LAUNCHER),          
3147                                                  PackageManager.MATCH_DEFAULT_ONLY);                               
3148                                          if (matched == null) {                                                    
3149                                              // Try to find the best match activity.                               
3150                                              Intent intent = pm.getLaunchIntentForPackage(                         
3151                                                      cn.getPackageName());                                         
3152                                              if (intent != null) {                                                 
3153                                                  cn = intent.getComponent();                                       
3154                                                  appInfo = addedOrUpdatedApps.get(cn);                             
3155                                              }                                                                     
3156                                                                                                                    
3157                                              if ((intent == null) || (appInfo == null)) {                          
3158                                                  removedShortcuts.add(si);                                         
3159                                                  continue;                                                         
3160                                              }                                                                     
3161                                              si.promisedIntent = intent;                                           
3162                                          }                                                                         
3163                                      }                                                                             
3164                                                                                                                    
3165                                      // Restore the shortcut.                                                      
3166                                      si.intent = si.promisedIntent;                                                
3167                                      si.promisedIntent = null;                                                     
3168                                      si.status &= ~ShortcutInfo.FLAG_RESTORED_ICON                                 
3169                                              & ~ShortcutInfo.FLAG_AUTOINTALL_ICON                                  
3170                                              & ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;                          
3171                                                                                                                    
3172                                      infoUpdated = true;                                                           
3173                                      si.updateIcon(mIconCache);                                                    
3174                                  }                                                                                 
3175                                                                                                                    
3176                                  if (appInfo != null && Intent.ACTION_MAIN.equals(si.intent.getAction())           
3177                                          && si.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {     
3178                                      si.updateIcon(mIconCache);                                                    
3179                                      si.title = appInfo.title.toString();                                          
3180                                      si.contentDescription = appInfo.contentDescription;                           
3181                                      infoUpdated = true;                                                           
3182                                  }                                                                                 
3183                                                                                                                    
3184                                  if ((si.isDisabled & ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE) != 0) {            
3185                                      // Since package was just updated, the target must be available now.          
3186                                      si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                   
3187                                      shortcutUpdated = true;                                                       
3188                                  }                                                                                 
3189                              }                                                                                     
3190                                                                                                                    
3191                              if (infoUpdated || shortcutUpdated) {                                                 
3192                                  updatedShortcuts.add(si);                                                         
3193                              }                                                                                     
3194                              if (infoUpdated) {                                                                    
3195                                  updateItemInDatabase(context, si);                                                
3196                              }                                                                                     
3197                          } else if (info instanceof LauncherAppWidgetInfo) {                                       
3198                              LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;                      
3199                              if (mUser.equals(widgetInfo.user)                                                     
3200                                      && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)   
3201                                      && packageSet.contains(widgetInfo.providerName.getPackageName())) {           
3202                                  widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;       
3203                                  widgets.add(widgetInfo);                                                          
3204                                  updateItemInDatabase(context, widgetInfo);                                        
3205                              }                                                                                     
3206                          }                                                                                         
3207                      }                                                                                             
3208                  }                                                                                                 
3209                                                                                                                    
3210                  if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {                                 
3211                      mHandler.post(new Runnable() {                                                                
3212                                                                                                                    
3213                          public void run() {                                                                       
3214                              Callbacks cb = getCallback();                                                         
3215                              if (callbacks == cb && cb != null) {                                                  
3216                                  callbacks.bindShortcutsChanged(                                                   
3217                                          updatedShortcuts, removedShortcuts, mUser);                               
3218                              }                                                                                     
3219                          }                                                                                         
3220                      });                                                                                           
3221                      if (!removedShortcuts.isEmpty()) {                                                            
3222                          deleteItemsFromDatabase(context, removedShortcuts);                                       
3223                      }                                                                                             
3224                  }                                                                                                 
3225                  if (!widgets.isEmpty()) {                                                                         
3226                      mHandler.post(new Runnable() {                                                                
3227                          public void run() {                                                                       
3228                              Callbacks cb = getCallback();                                                         
3229                              if (callbacks == cb && cb != null) {                                                  
3230                                  callbacks.bindWidgetsRestored(widgets);                                           
3231                              }                                                                                     
3232                          }                                                                                         
3233                      });                                                                                           
3234                  }                                                                                                 
3235              }                                                                                                     
3236                                                                                                                    
3237              final ArrayList<String> removedPackageNames =                                                         
3238                      new ArrayList<String>();                                                                      
3239              if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {                                                      
3240                  // Mark all packages in the broadcast to be removed                                               
3241                  removedPackageNames.addAll(Arrays.asList(packages));                                              
3242              } else if (mOp == OP_UPDATE) {                                                                        
3243                  // Mark disabled packages in the broadcast to be removed                                          
3244                  for (int i=0; i<N; i++) {                                                                         
3245                      if (isPackageDisabled(context, packages[i], mUser)) {                                         
3246                          removedPackageNames.add(packages[i]);                                                     
3247                      }                                                                                             
3248                  }                                                                                                 
3249              }                                                                                                     
3250                                                                                                                    
3251              if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                                       
3252                  final int removeReason;                                                                           
3253                  if (mOp == OP_UNAVAILABLE) {                                                                      
3254                      removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;                                      
3255                  } else {                                                                                          
3256                      // Remove all the components associated with this package                                     
3257                      for (String pn : removedPackageNames) {                                                       
3258                          deletePackageFromDatabase(context, pn, mUser);                                            
3259                      }                                                                                             
3260                      // Remove all the specific components                                                         
3261                      for (AppInfo a : removedApps) {                                                               
3262                          ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName, mUser);          
3263                          deleteItemsFromDatabase(context, infos);                                                  
3264                      }                                                                                             
3265                      removeReason = 0;                                                                             
3266                  }                                                                                                 
3267                                                                                                                    
3268                  // Remove any queued items from the install queue                                                 
3269                  InstallShortcutReceiver.removeFromInstallQueue(context, removedPackageNames, mUser);              
3270                  // Call the components-removed callback                                                           
3271                  mHandler.post(new Runnable() {                                                                    
3272                      public void run() {                                                                           
3273                          Callbacks cb = getCallback();                                                             
3274                          if (callbacks == cb && cb != null) {                                                      
3275                              callbacks.bindComponentsRemoved(                                                      
3276                                      removedPackageNames, removedApps, mUser, removeReason);                       
3277                          }                                                                                         
3278                      }                                                                                             
3279                  });                                                                                               
3280              }                                                                                                     
3281                                                                                                                    
3282              final ArrayList<Object> widgetsAndShortcuts =                                                         
3283                      getSortedWidgetsAndShortcuts(context);                                                        
3284              mHandler.post(new Runnable() {                                                                        
3285                  @Override                                                                                         
3286                  public void run() {                                                                               
3287                      Callbacks cb = getCallback();                                                                 
3288                      if (callbacks == cb && cb != null) {                                                          
3289                          callbacks.bindPackagesUpdated(widgetsAndShortcuts);                                       
3290                      }                                                                                             
3291                  }                                                                                                 
3292              });                                                                                                   
3293                                                                                                                    
3294              // Write all the logs to disk                                                                         
3295              mHandler.post(new Runnable() {                                                                        
3296                  public void run() {                                                                               
3297                      Callbacks cb = getCallback();                                                                 
3298                      if (callbacks == cb && cb != null) {                                                          
3299                          callbacks.dumpLogsToLocalData();                                                          
3300                      }                                                                                             
3301                  }                                                                                                 
3302              });                                                                                                   
3303          }                                                                                                         
3304      }                                                                                                             
3305                                                                                                                    
3306      public static List<LauncherAppWidgetProviderInfo> getWidgetProviders(Context context) {                       
3307          synchronized (sBgLock) {                                                                                  
3308              if (sBgWidgetProviders != null && !sWidgetProvidersDirty) {                                           
3309                  return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());                 
3310              }                                                                                                     
3311              sBgWidgetProviders = new HashMap<ComponentName, LauncherAppWidgetProviderInfo>();                     
3312              List<AppWidgetProviderInfo> widgets =                                                                 
3313                      AppWidgetManagerCompat.getInstance(context).getAllProviders();                                
3314              LauncherAppWidgetProviderInfo info;                                                                   
3315              for (AppWidgetProviderInfo pInfo : widgets) {                                                         
3316                  info = LauncherAppWidgetProviderInfo.fromProviderInfo(context, pInfo);                            
3317                  sBgWidgetProviders.put(info.provider, info);                                                      
3318              }                                                                                                     
3319                                                                                                                    
3320              Collection<CustomAppWidget> customWidgets = Launcher.getCustomAppWidgets().values();                  
3321              for (CustomAppWidget widget : customWidgets) {                                                        
3322                  info = new LauncherAppWidgetProviderInfo(context, widget);                                        
3323                  sBgWidgetProviders.put(info.provider, info);                                                      
3324              }                                                                                                     
3325              sWidgetProvidersDirty = false;                                                                        
3326              return new ArrayList<LauncherAppWidgetProviderInfo>(sBgWidgetProviders.values());                     
3327          }                                                                                                         
3328      }                                                                                                             
3329                                                                                                                    
3330      public static LauncherAppWidgetProviderInfo getProviderInfo(Context ctx, ComponentName name) {                
3331          synchronized (sBgLock) {                                                                                  
3332              if (sBgWidgetProviders == null) {                                                                     
3333                  getWidgetProviders(ctx);                                                                          
3334              }                                                                                                     
3335              return sBgWidgetProviders.get(name);                                                                  
3336          }                                                                                                         
3337      }                                                                                                             
3338                                                                                                                    
3339      // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                              
3340      public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                               
3341          PackageManager packageManager = context.getPackageManager();                                              
3342          final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                                    
3343          widgetsAndShortcuts.addAll(getWidgetProviders(context));                                                  
3344          Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                                       
3345          widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));                     
3346          Collections.sort(widgetsAndShortcuts, new WidgetAndShortcutNameComparator(context));                      
3347          return widgetsAndShortcuts;                                                                               
3348      }                                                                                                             
3349                                                                                                                    
3350      private static boolean isPackageDisabled(Context context, String packageName,                                 
3351              UserHandleCompat user) {                                                                              
3352          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3353          return !launcherApps.isPackageEnabledForProfile(packageName, user);                                       
3354      }                                                                                                             
3355                                                                                                                    
3356      public static boolean isValidPackageActivity(Context context, ComponentName cn,                               
3357              UserHandleCompat user) {                                                                              
3358          if (cn == null) {                                                                                         
3359              return false;                                                                                         
3360          }                                                                                                         
3361          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3362          if (!launcherApps.isPackageEnabledForProfile(cn.getPackageName(), user)) {                                
3363              return false;                                                                                         
3364          }                                                                                                         
3365          return launcherApps.isActivityEnabledForProfile(cn, user);                                                
3366      }                                                                                                             
3367                                                                                                                    
3368      public static boolean isValidPackage(Context context, String packageName,                                     
3369              UserHandleCompat user) {                                                                              
3370          if (packageName == null) {                                                                                
3371              return false;                                                                                         
3372          }                                                                                                         
3373          final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);                          
3374          return launcherApps.isPackageEnabledForProfile(packageName, user);                                        
3375      }                                                                                                             
3376                                                                                                                    
3377      /**                                                                                                           
3378       * Make an ShortcutInfo object for a restored application or shortcut item that points                        
3379       * to a package that is not yet installed on the system.                                                      
3380       */                                                                                                           
3381      public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent,                         
3382              int promiseType) {                                                                                    
3383          final ShortcutInfo info = new ShortcutInfo();                                                             
3384          info.user = UserHandleCompat.myUserHandle();                                                              
3385          mIconCache.getTitleAndIcon(info, intent, info.user, true);                                                

3386                                                                                                                    
3387          if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {                                               
3388              String title = (cursor != null) ? cursor.getString(titleIndex) : null;                                
3389              if (!TextUtils.isEmpty(title)) {                                                                      
3390                  info.title = title;                                                                               
3391              }                                                                                                     
3392              info.status = ShortcutInfo.FLAG_RESTORED_ICON;                                                        
3393          } else if  ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {                                     
3394              if (TextUtils.isEmpty(info.title)) {                                                                  
3395                  info.title = (cursor != null) ? cursor.getString(titleIndex) : "";                                
3396              }                                                                                                     
3397              info.status = ShortcutInfo.FLAG_AUTOINTALL_ICON;                                                      
3398          } else {                                                                                                  
3399              throw new InvalidParameterException("Invalid restoreType " + promiseType);                            
3400          }                                                                                                         
3401                                                                                                                    
3402          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3403                  info.title.toString(), info.user);                                                                
3404          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3405          info.promisedIntent = intent;                                                                             
3406          return info;                                                                                              
3407      }                                                                                                             
3408                                                                                                                    
3409      /**                                                                                                           
3410       * Make an Intent object for a restored application or shortcut item that points                              
3411       * to the market page for the item.                                                                           
3412       */                                                                                                           
3413      private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                              
3414          ComponentName componentName = intent.getComponent();                                                      
3415          return getMarketIntent(componentName.getPackageName());                                                   
3416      }                                                                                                             
3417                                                                                                                    
3418      static Intent getMarketIntent(String packageName) {                                                           
3419          return new Intent(Intent.ACTION_VIEW)                                                                     
3420              .setData(new Uri.Builder()                                                                            
3421                  .scheme("market")                                                                                 
3422                  .authority("details")                                                                             
3423                  .appendQueryParameter("id", packageName)                                                          
3424                  .build());                                                                                        
3425      }                                                                                                             
3426                                                                                                                    
3427      /**                                                                                                           
3428       * This is called from the code that adds shortcuts from the intent receiver.  This                           
3429       * doesn't have a Cursor, but                                                                                 
3430       */                                                                                                           
3431      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    
3432              UserHandleCompat user, Context context) {                                                             
3433          return getShortcutInfo(manager, intent, user, context, null, -1, -1, null, false);                        
3434      }                                                                                                             
3435                                                                                                                    
3436      /**                                                                                                           
3437       * Make an ShortcutInfo object for a shortcut that is an application.                                         
3438       *                                                                                                            
3439       * If c is not null, then it will be used to fill in missing data like the title and icon.                    
3440       */                                                                                                           
3441      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent,                                    

3442              UserHandleCompat user, Context context, Cursor c, int iconIndex, int titleIndex,                      
3443              HashMap<Object, CharSequence> labelCache, boolean allowMissingTarget) {                               

3444          if (user == null) {                                                                                       
3445              Log.d(TAG, "Null user found in getShortcutInfo");                                                     
3446              return null;                                                                                          
3447          }                                                                                                         
3448                                                                                                                    
3449          ComponentName componentName = intent.getComponent();                                                      
3450          if (componentName == null) {                                                                              
3451              Log.d(TAG, "Missing component found in getShortcutInfo: " + componentName);                           
3452              return null;                                                                                          
3453          }                                                                                                         
3454                                                                                                                    
3455          Intent newIntent = new Intent(intent.getAction(), null);                                                  
3456          newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                          
3457          newIntent.setComponent(componentName);                                                                    
3458          LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);                          
3459          if ((lai == null) && !allowMissingTarget) {                                                               
3460              Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);                            
3461              return null;                                                                                          
3462          }                                                                                                         
3463                                                                                                                    
3464          final ShortcutInfo info = new ShortcutInfo();                                                             
3465                                                                                                                    
3466          // the resource -- This may implicitly give us back the fallback icon,                                    
3467          // but don't worry about that.  All we're doing with usingFallbackIcon is                                 
3468          // to avoid saving lots of copies of that in the database, and most apps                                  
3469          // have icons anyway.                                                                                     
3470          Bitmap icon = mIconCache.getIcon(componentName, lai, labelCache);                                         
3471                                                                                                                    
3472          // the db                                                                                                 
3473          if (icon == null) {                                                                                       
3474              if (c != null) {                                                                                      
3475                  icon = getIconFromCursor(c, iconIndex, context);                                                  
3476              }                                                                                                     
3477          }                                                                                                         
3478          // the fallback icon                                                                                      
3479          if (icon == null) {                                                                                       
3480              icon = mIconCache.getDefaultIcon(user);                                                               
3481              info.usingFallbackIcon = true;                                                                        
3482          }                                                                                                         
3483          info.setIcon(icon);                                                                                       
3484                                                                                                                    
3485          // From the cache.                                                                                        
3486          if (labelCache != null) {                                                                                 
3487              info.title = labelCache.get(componentName);                                                           
3488          }                                                                                                         
3489                                                                                                                    
3490          // from the resource                                                                                      
3491          if (info.title == null && lai != null) {                                                                  
3492              info.title = lai.getLabel();                                                                          
3493              if (labelCache != null) {                                                                             
3494                  labelCache.put(componentName, info.title);                                                        
3495              }                                                                                                     
3496          }                                                                                                         






3497          // from the db                                                                                            
3498          if (info.title == null) {                                                                                 
3499              if (c != null) {                                                                                      
3500                  info.title =  c.getString(titleIndex);                                                            
3501              }                                                                                                     
3502          }                                                                                                         




3503          // fall back to the class name of the activity                                                            
3504          if (info.title == null) {                                                                                 
3505              info.title = componentName.getClassName();                                                            
3506          }                                                                                                         

3507          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                         
3508          info.user = user;                                                                                         
3509          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3510                  info.title.toString(), info.user);                                                                
3511          return info;                                                                                              
3512      }                                                                                                             
3513                                                                                                                    
3514      static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                                        
3515              ItemInfoFilter f) {                                                                                   
3516          HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                                     
3517          for (ItemInfo i : infos) {                                                                                
3518              if (i instanceof ShortcutInfo) {                                                                      
3519                  ShortcutInfo info = (ShortcutInfo) i;                                                             
3520                  ComponentName cn = info.getTargetComponent();                                                     
3521                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3522                      filtered.add(info);                                                                           
3523                  }                                                                                                 
3524              } else if (i instanceof FolderInfo) {                                                                 
3525                  FolderInfo info = (FolderInfo) i;                                                                 
3526                  for (ShortcutInfo s : info.contents) {                                                            
3527                      ComponentName cn = s.getTargetComponent();                                                    
3528                      if (cn != null && f.filterItem(info, s, cn)) {                                                
3529                          filtered.add(s);                                                                          
3530                      }                                                                                             
3531                  }                                                                                                 
3532              } else if (i instanceof LauncherAppWidgetInfo) {                                                      
3533                  LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                           
3534                  ComponentName cn = info.providerName;                                                             
3535                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3536                      filtered.add(info);                                                                           
3537                  }                                                                                                 
3538              }                                                                                                     
3539          }                                                                                                         
3540          return new ArrayList<ItemInfo>(filtered);                                                                 
3541      }                                                                                                             
3542                                                                                                                    
3543      private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname,                            
3544              final UserHandleCompat user) {                                                                        
3545          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
3546              @Override                                                                                             
3547              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
3548                  if (info.user == null) {                                                                          
3549                      return cn.equals(cname);                                                                      
3550                  } else {                                                                                          
3551                      return cn.equals(cname) && info.user.equals(user);                                            
3552                  }                                                                                                 
3553              }                                                                                                     
3554          };                                                                                                        
3555          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
3556      }                                                                                                             
3557                                                                                                                    
3558      /**                                                                                                           
3559       * Make an ShortcutInfo object for a shortcut that isn't an application.                                      
3560       */                                                                                                           
3561      private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                               
3562              int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,                        
3563              int titleIndex) {                                                                                     
3564                                                                                                                    
3565          Bitmap icon = null;                                                                                       
3566          final ShortcutInfo info = new ShortcutInfo();                                                             
3567          // Non-app shortcuts are only supported for current user.                                                 
3568          info.user = UserHandleCompat.myUserHandle();                                                              
3569          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3570                                                                                                                    
3571          // TODO: If there's an explicit component and we can't install that, delete it.                           
3572                                                                                                                    
3573          info.title = c.getString(titleIndex);                                                                     
3574                                                                                                                    
3575          int iconType = c.getInt(iconTypeIndex);                                                                   
3576          switch (iconType) {                                                                                       
3577          case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                                       
3578              String packageName = c.getString(iconPackageIndex);                                                   
3579              String resourceName = c.getString(iconResourceIndex);                                                 
3580              info.customIcon = false;                                                                              
3581              // the resource                                                                                       
3582              icon = Utilities.createIconBitmap(packageName, resourceName, mIconCache, context);                    
3583              // the db                                                                                             
3584              if (icon == null) {                                                                                   
3585                  icon = getIconFromCursor(c, iconIndex, context);                                                  

3586              }                                                                                                     
3587              // the fallback icon                                                                                  
3588              if (icon == null) {                                                                                   
3589                  icon = mIconCache.getDefaultIcon(info.user);                                                      
3590                  info.usingFallbackIcon = true;                                                                    
3591              }                                                                                                     
3592              break;                                                                                                
3593          case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                         
3594              icon = getIconFromCursor(c, iconIndex, context);                                                      

3595              if (icon == null) {                                                                                   
3596                  icon = mIconCache.getDefaultIcon(info.user);                                                      
3597                  info.customIcon = false;                                                                          
3598                  info.usingFallbackIcon = true;                                                                    
3599              } else {                                                                                              
3600                  info.customIcon = true;                                                                           
3601              }                                                                                                     
3602              break;                                                                                                
3603          default:                                                                                                  
3604              icon = mIconCache.getDefaultIcon(info.user);                                                          
3605              info.usingFallbackIcon = true;                                                                        
3606              info.customIcon = false;                                                                              
3607              break;                                                                                                
3608          }                                                                                                         
3609          info.setIcon(icon);                                                                                       
3610          return info;                                                                                              
3611      }                                                                                                             
3612                                                                                                                    
3613      Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                          
3614          @SuppressWarnings("all") // suppress dead code warning                                                    
3615          final boolean debug = false;                                                                              
3616          if (debug) {                                                                                              
3617              Log.d(TAG, "getIconFromCursor app="                                                                   
3618                      + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));                    
3619          }                                                                                                         
3620          byte[] data = c.getBlob(iconIndex);                                                                       
3621          try {                                                                                                     
3622              return Utilities.createIconBitmap(                                                                    
3623                      BitmapFactory.decodeByteArray(data, 0, data.length), context);                                
3624          } catch (Exception e) {                                                                                   
3625              return null;                                                                                          
3626          }                                                                                                         
3627      }                                                                                                             
3628                                                                                                                    
3629      ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {                                           
3630          Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                                    
3631          String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                            
3632          Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                                  
3633                                                                                                                    
3634          if (intent == null) {                                                                                     
3635              // If the intent is null, we can't construct a valid ShortcutInfo, so we return null                  
3636              Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                           
3637              return null;                                                                                          
3638          }                                                                                                         
3639                                                                                                                    
3640          Bitmap icon = null;                                                                                       
3641          boolean customIcon = false;                                                                               
3642          ShortcutIconResource iconResource = null;                                                                 
3643                                                                                                                    
3644          if (bitmap instanceof Bitmap) {                                                                           
3645              icon = Utilities.createIconBitmap((Bitmap) bitmap, context);                                          
3646              customIcon = true;                                                                                    
3647          } else {                                                                                                  
3648              Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);                      
3649              if (extra instanceof ShortcutIconResource) {                                                          
3650                  iconResource = (ShortcutIconResource) extra;                                                      
3651                  icon = Utilities.createIconBitmap(iconResource.packageName,                                       
3652                          iconResource.resourceName, mIconCache, context);                                          
3653              }                                                                                                     
3654          }                                                                                                         
3655                                                                                                                    
3656          final ShortcutInfo info = new ShortcutInfo();                                                             
3657                                                                                                                    
3658          // Only support intents for current user for now. Intents sent from other                                 
3659          // users wouldn't get here without intent forwarding anyway.                                              
3660          info.user = UserHandleCompat.myUserHandle();                                                              
3661          if (icon == null) {                                                                                       
3662              icon = mIconCache.getDefaultIcon(info.user);                                                          
3663              info.usingFallbackIcon = true;                                                                        
3664          }                                                                                                         
3665          info.setIcon(icon);                                                                                       
3666                                                                                                                    
3667          info.title = name;                                                                                        
3668          info.contentDescription = mUserManager.getBadgedLabelForUser(                                             
3669                  info.title.toString(), info.user);                                                                
3670          info.intent = intent;                                                                                     
3671          info.customIcon = customIcon;                                                                             
3672          info.iconResource = iconResource;                                                                         
3673                                                                                                                    
3674          return info;                                                                                              
3675      }                                                                                                             
3676                                                                                                                    
3677      boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,                      
3678              int iconIndex) {                                                                                      
3679          // If apps can't be on SD, don't even bother.                                                             
3680          if (!mAppsCanBeOnRemoveableStorage) {                                                                     
3681              return false;                                                                                         
3682          }                                                                                                         
3683          // If this icon doesn't have a custom icon, check to see                                                  
3684          // what's stored in the DB, and if it doesn't match what                                                  
3685          // we're going to show, store what we are going to show back                                              
3686          // into the DB.  We do this so when we're loading, if the                                                 
3687          // package manager can't find an icon (for example because                                                
3688          // the app is on SD) then we can use that instead.                                                        
3689          if (!info.customIcon && !info.usingFallbackIcon) {                                                        
3690              cache.put(info, c.getBlob(iconIndex));                                                                
3691              return true;                                                                                          
3692          }                                                                                                         
3693          return false;                                                                                             
3694      }                                                                                                             
3695      void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                                       
3696          boolean needSave = false;                                                                                 
3697          try {                                                                                                     
3698              if (data != null) {                                                                                   
3699                  Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                               
3700                  Bitmap loaded = info.getIcon(mIconCache);                                                         
3701                  needSave = !saved.sameAs(loaded);                                                                 
3702              } else {                                                                                              
3703                  needSave = true;                                                                                  
3704              }                                                                                                     
3705          } catch (Exception e) {                                                                                   
3706              needSave = true;                                                                                      
3707          }                                                                                                         
3708          if (needSave) {                                                                                           
3709              Log.d(TAG, "going to save icon bitmap for info=" + info);                                             
3710              // This is slower than is ideal, but this only happens once                                           
3711              // or when the app is updated with a new icon.                                                        
3712              updateItemInDatabase(context, info);                                                                  
3713          }                                                                                                         
3714      }                                                                                                             
3715                                                                                                                    
3716      /**                                                                                                           
3717       * Return an existing FolderInfo object if we have encountered this ID previously,                            
3718       * or make a new one.                                                                                         
3719       */                                                                                                           
3720      private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {                      
3721          // See if a placeholder was created for us already                                                        
3722          FolderInfo folderInfo = folders.get(id);                                                                  
3723          if (folderInfo == null) {                                                                                 
3724              // No placeholder -- create a new instance                                                            
3725              folderInfo = new FolderInfo();                                                                        
3726              folders.put(id, folderInfo);                                                                          
3727          }                                                                                                         
3728          return folderInfo;                                                                                        
3729      }                                                                                                             
3730                                                                                                                    
3731      public static final Comparator<AppInfo> getAppNameComparator() {                                              
3732          final Collator collator = Collator.getInstance();                                                         
3733          return new Comparator<AppInfo>() {                                                                        
3734              public final int compare(AppInfo a, AppInfo b) {                                                      
3735                  if (a.user.equals(b.user)) {                                                                      
3736                      int result = collator.compare(a.title.toString().trim(),                                      
3737                              b.title.toString().trim());                                                           
3738                      if (result == 0) {                                                                            
3739                          result = a.componentName.compareTo(b.componentName);                                      
3740                      }                                                                                             
3741                      return result;                                                                                
3742                  } else {                                                                                          
3743                      // TODO Need to figure out rules for sorting                                                  
3744                      // profiles, this puts work second.                                                           
3745                      return a.user.toString().compareTo(b.user.toString());                                        
3746                  }                                                                                                 
3747              }                                                                                                     
3748          };                                                                                                        
3749      }                                                                                                             
3750      public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                           
3751              = new Comparator<AppInfo>() {                                                                         
3752          public final int compare(AppInfo a, AppInfo b) {                                                          
3753              if (a.firstInstallTime < b.firstInstallTime) return 1;                                                
3754              if (a.firstInstallTime > b.firstInstallTime) return -1;                                               
3755              return 0;                                                                                             
3756          }                                                                                                         
3757      };                                                                                                            
3758      static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                                      
3759          if (info.activityInfo != null) {                                                                          
3760              return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);                      
3761          } else {                                                                                                  
3762              return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);                        
3763          }                                                                                                         
3764      }                                                                                                             
3765      public static class ShortcutNameComparator implements Comparator<LauncherActivityInfoCompat> {                
3766          private Collator mCollator;                                                                               
3767          private HashMap<Object, CharSequence> mLabelCache;                                                        
3768          ShortcutNameComparator(PackageManager pm) {                                                               
3769              mLabelCache = new HashMap<Object, CharSequence>();                                                    
3770              mCollator = Collator.getInstance();                                                                   
3771          }                                                                                                         
3772          ShortcutNameComparator(HashMap<Object, CharSequence> labelCache) {                                        
3773              mLabelCache = labelCache;                                                                             
3774              mCollator = Collator.getInstance();                                                                   
3775          }                                                                                                         
3776          public final int compare(LauncherActivityInfoCompat a, LauncherActivityInfoCompat b) {                    
3777              String labelA, labelB;                                                                                
3778              ComponentName keyA = a.getComponentName();                                                            
3779              ComponentName keyB = b.getComponentName();                                                            
3780              if (mLabelCache.containsKey(keyA)) {                                                                  
3781                  labelA = mLabelCache.get(keyA).toString();                                                        
3782              } else {                                                                                              
3783                  labelA = a.getLabel().toString().trim();                                                          
3784                                                                                                                    
3785                  mLabelCache.put(keyA, labelA);                                                                    
3786              }                                                                                                     
3787              if (mLabelCache.containsKey(keyB)) {                                                                  
3788                  labelB = mLabelCache.get(keyB).toString();                                                        
3789              } else {                                                                                              
3790                  labelB = b.getLabel().toString().trim();                                                          
3791                                                                                                                    
3792                  mLabelCache.put(keyB, labelB);                                                                    
3793              }                                                                                                     
3794              return mCollator.compare(labelA, labelB);                                                             
3795          }                                                                                                         
3796      };                                                                                                            

3797      public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                           
3798          private final AppWidgetManagerCompat mManager;                                                            
3799          private final PackageManager mPackageManager;                                                             
3800          private final HashMap<Object, String> mLabelCache;                                                        
3801          private final Collator mCollator;                                                                         
3802                                                                                                                    
3803          WidgetAndShortcutNameComparator(Context context) {                                                        
3804              mManager = AppWidgetManagerCompat.getInstance(context);                                               
3805              mPackageManager = context.getPackageManager();                                                        
3806              mLabelCache = new HashMap<Object, String>();                                                          
3807              mCollator = Collator.getInstance();                                                                   
3808          }                                                                                                         
3809          public final int compare(Object a, Object b) {                                                            
3810              String labelA, labelB;                                                                                
3811              if (mLabelCache.containsKey(a)) {                                                                     
3812                  labelA = mLabelCache.get(a);                                                                      
3813              } else {                                                                                              
3814                  labelA = (a instanceof LauncherAppWidgetProviderInfo)                                             
3815                          ? mManager.loadLabel((LauncherAppWidgetProviderInfo) a)                                   
3816                          : ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                         
3817                  mLabelCache.put(a, labelA);                                                                       
3818              }                                                                                                     
3819              if (mLabelCache.containsKey(b)) {                                                                     
3820                  labelB = mLabelCache.get(b);                                                                      
3821              } else {                                                                                              
3822                  labelB = (b instanceof LauncherAppWidgetProviderInfo)                                             
3823                          ? mManager.loadLabel((LauncherAppWidgetProviderInfo) b)                                   
3824                          : ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                         
3825                  mLabelCache.put(b, labelB);                                                                       
3826              }                                                                                                     
3827              return mCollator.compare(labelA, labelB);                                                             
3828          }                                                                                                         
3829      };                                                                                                            
3830                                                                                                                    
3831      static boolean isValidProvider(AppWidgetProviderInfo provider) {                                              
3832          return (provider != null) && (provider.provider != null)                                                  
3833                  && (provider.provider.getPackageName() != null);                                                  
3834      }                                                                                                             
3835                                                                                                                    
3836      public void dumpState() {                                                                                     
3837          Log.d(TAG, "mCallbacks=" + mCallbacks);                                                                   
3838          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                           
3839          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                         
3840          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);                     
3841          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);                   
3842          if (mLoaderTask != null) {                                                                                
3843              mLoaderTask.dumpState();                                                                              
3844          } else {                                                                                                  
3845              Log.d(TAG, "mLoaderTask=null");                                                                       
3846          }                                                                                                         
3847      }                                                                                                             
3848                                                                                                                    
3849      public Callbacks getCallback() {                                                                              
3850          return mCallbacks != null ? mCallbacks.get() : null;                                                      
3851      }                                                                                                             
3852  }